Configuration

Daniel van Vugt daniel.van.vugt at canonical.com
Wed Apr 17 01:37:53 UTC 2013


I could see the configuration stuff becoming unwieldy, though have not 
had to use it yet so am not aware of the intent or requirements.

My only request is to try and keep any new solution simple. Reconsider 
if and where "configuration" needs to be a class at all.

Also consider using the abbreviation "Config". The reasoning being that 
humans see words as symbols and frequently recognize them by shape 
alone. We do not look at individual letters, so try not to have 
SomeLongClassNameConfiguration. It hinders readability.


On 16/04/13 22:28, Alan Griffiths wrote:
> We've agreed that the DefaultServerConfiguration is becoming an unwieldy
> mess. (At least racarr and I have.)
>
> Before coding anything up I want to propose a few principles to see if
> there's any agreement.
>
> With a few exceptions the structural classes that are build by
> DefaultServerConfiguration take explicit shared pointers to their
> dependencies. This approach makes dependencies explicit - which, for
> example, makes use of test doubles clear when testing.
>
> The exceptions are DisplayServer (which takes ServerConfiguration by
> reference) and InputManager & DispatcherController (which take
> InputConfiguration by shared_ptr). There's also an MP under review that
> has SessionManager take ShellConfiguration by shared_ptr. (I think the
> use of shared_ptr in these three exceptions is misleading but, if we
> agree that concealing dependencies line this is bad, the shared_ptr is
> probably moot.)
>
> My concern with this latter approach is that it couples the dependencies
> of the class to an interface - and makes reuse of mir by supplying
> alternative implementations a little harder - as it is no longer always
> a matter of overriding a factory method in DefaultServerConfiguration.
>
> However, I've thought myself around in a circle trying to improve
> things. (Sharing because someone out there will contribute the insight
> I'm lacking.)
>
> ~~~~
>
> What I'd like to see is that these inter-dependencies are built up
> within the ServerConfiguration class hierarchy in a way that allows
> alternative implementations to be substituted.
>
> What I'm not sure is possible (without exposing lots of implementation
> as template code) is how flexible such a solution is.
>
> E.g. (Approach #1)
>
> class ServerConfiguration { /* interface supplying dependencies of
> DisplayServer */ };
>
> class DefaultSubsystem1Dependencies : public virtual ServerConfiguration
>    { /* interface supplying dependencies of Subsystem1 */ };
> ...
> class DefaultSubsystem5Dependencies : public virtual ServerConfiguration
>    { /* interface supplying dependencies of Subsystem5 */ };
>
> class DefaultDependencies :
>      public virtual DefaultSubsystem1Dependencies,
>      ...
>      public virtual DefaultSubsystem5Dependencies
> { /* all the dependencies */ };
>
> class DefaultSubsystem1 : public virtual ServerConfiguration, virtual
> DefaultDependencies
>    { /* implementation building Subsystem1 */ };
> ...
> class DefaultSubsystem5 : public virtual ServerConfiguration, virtual
> DefaultDependencies
>    { /* implementation building Subsystem5 */ };
>
> class DefaultServerConfiguration :
>      public virtual ServerConfiguration,
>      virtual DefaultSubsystem1,
>      ...
>      virtual DefaultSubsystem5
> { /* combines the implementations */ };
>
> The inflexibility exists because the DefaultSubsystemX classes have to
> derive from any DefaultSubsystemY interfaces that contain functions they
> implement. Some flexibility could be attained using typelists, but not
> without making the implementation classes templates. (Which pulls all
> the implementation knowledge into a header - even worse than the current
> all the implementation knowledge into a translation unit.)
>
> Another issue with this approach is that there is nothing keeping the
> dependencies in DefaultSubsystem1Dependencies correct (as long as a
> needed function is declared in some interface everything compiles).
>
> So, with this approach, there seems to be little value in the
> DefaultSubsystemXDependencies interfaces - everything could be placed
> directly into DefaultDependencies. Hence "Approach #2"...
>
> ~~~~
>
> Approach #2
>
> class ServerConfiguration { /* interface supplying dependencies of
> DisplayServer */ };
>
> class DefaultDependencies : public  virtual ServerConfiguration
> { /* all the dependencies */ };
>
> class DefaultSubsystem1 : public virtual ServerConfiguration, virtual
> DefaultDependencies
>    { /* implementation building Subsystem1 */ };
> ...
> class DefaultSubsystem5 : public virtual ServerConfiguration, virtual
> DefaultDependencies
>    { /* implementation building Subsystem5 */ };
>
> class DefaultServerConfiguration :
>      public virtual ServerConfiguration,
>      virtual DefaultSubsystem1,
>      ...
>      virtual DefaultSubsystem5
> { /* combines the implementations */ };
>
> Now this allows someone to come along with a:
>
> class NonDefaultSubsystem3 : public virtual ServerConfiguration, virtual
> DefaultDependencies
>    { /* implementation building Subsystem3 */ };
>
> class NonDefaultServerConfiguration :
>      public virtual ServerConfiguration,
>      virtual DefaultSubsystem1,
>      ...
>      NonDefaultSubsystem3,
>      ...
>      virtual DefaultSubsystem5
> { /* combines the implementations */ };
>
> But this doesn't gain much over simply splitting up the implementation
> file. (Approach #3)
>
> ~~~~
>
> class ServerConfiguration { /* interface supplying dependencies of
> DisplayServer */ };
>
> class DefaultServerConfiguration :
>      public ServerConfiguration
> { /* declare the factory functions */ };
>
> // implentation file 1
> DefaultServerConfiguration methods to build Subsystem1
> ...
> // implentation file 5
> DefaultServerConfiguration methods to build Subsystem5
>
> And someone can come along with a:
>
> class NonDefaultServerConfiguration :
>      public DefaultServerConfiguration
> { /* override some of the factory functions */ };
>
> And apart from splitting up a monster .cpp we're back where we started.
> (Splitting up the implementation file isn't a bad idea though.)
>



More information about the Mir-devel mailing list