Simplify our forward-facing APIs by introducing sane defaults

XMLWordPrintableJSON

    • Type: Task
    • Resolution: Unresolved
    • Priority: Major - P3
    • None
    • Affects Version/s: None
    • Component/s: None
    • Replication
    • None
    • None
    • None
    • None
    • None
    • None
    • None

      Some of our C++ classes and methods require the user to pass in an instance of a class, rather than the class or method itself generating the instance.

      This makes using our APIs needlessly complicated, especially for those on other teams. It also worsens modularity, since it prevents us from further reducing the scope of our user-facing API.

      As an example, the `repl::ReplicationCoordinatorExternalStateImpl` class has only one use in a file outside of repl:

      // https://github.com/10gen/mongo/blob/master/src/mongo/db/find_one_bm.cpp?plain=1#L100-L113
          auto si = makeStorageInterface(svcCtx);
          auto rp = makeReplicationProcess(svcCtx, si);
      
          repl::ReplicationCoordinator::set(
              svcCtx,
              std::make_unique<repl::ReplicationCoordinatorImpl>(
                  svcCtx,
                  getGlobalReplSettings(),
                  std::make_unique<repl::ReplicationCoordinatorExternalStateImpl>(svcCtx, si, rp),
                  makeReplicationExecutor(svcCtx),
                  std::make_unique<repl::TopologyCoordinator>(makeTopologyCoordinatorOptions()),
                  rp,
                  si,
                  SecureRandom().nextInt64()));
      

      Because the `repl::ReplicationCoordinatorImpl` constructor requires a `std::unique_ptr<ReplicationCoordinatorExternalState>`, this code is forced to depend on `repl::ReplicationCoordinatorExternalStateImpl`, and the external state impl class cannot be made MONGO_MOD_PARENT_PRIVATE. However, creating a `repl::ReplicationCoordinatorExternalStateImpl` using the service context, storage interface, and replication process provided is a reasonable default for `repl::ReplicationCoordinatorImpl`.

      The following is a very noncomprehensive list of alternative API patterns that would simplify the code above without changing the behavior.

      • Factory pattern
        auto replCoord = repl::ReplicationCoordinatorImplFactory::create(
            // or repl::ReplicationCoordinatorImpl::Factory::create
            svcCtx, 
            getGlobalReplSettings()
        );
        
      • Builder pattern
        auto replCoord = std::make_unique<repl::ReplicationCoordinatorImpl>(
            svcCtx, 
            getGlobalReplSettings(),
        );
        
        auto customReplCoord = std::make_unique<repl::ReplicationCoordinatorImpl>(
            svcCtx, 
            getGlobalReplSettings(),
            myPrngSeed,
        )
          ->setExternalStateImpl(myExternalState)
          ->setExecutor(myExecutor)
          ->setSettings(mySettings)
          ->setTopologyCoordinator(myTopoCoord)
          ->setReplicationProcess(myReplicationProcess)
          ->setStorageInterface(myStorage);
        
        /** or with overload resolution: */
        auto customReplCoord = std::make_unique<repl::ReplicationCoordinatorImpl>(
            svcCtx, 
            getGlobalReplSettings(),
            myPrngSeed,
        )
          ->set(myExternalState)
          ->set(myExecutor)
          /** ... */
          ->set(myStorage);
        
      • boost::optional Arguments
        auto replCoord = std::make_unqiue<repl::ReplicationCoordinatorImpl>(
          svcCtx,
          getGlobalReplSettings(),
          boost::none, // or alternatively, make an alias for this: `using repl::default = boost::none;`
          boost::none,
          boost::none,
          boost::none,
          boost::none,
          SecureRandom().nextInt64()
        );
        
      • "Options" struct and designated initializers
        auto replCoord = std::make_unqiue<repl::ReplicationCoordinatorImpl>(
          { /** of type repl::ReplicationCoordinatorImpl::Options */
            .serviceContext = svcCtx,
            .replSettings = getGlobalReplSettings()
          });
        

            Assignee:
            Unassigned
            Reporter:
            Joseph Obaraye
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated: