-
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() });