2

I'm confused about applying the "Composition Root" (CR) to create aggregates in DDD. Seemann (2012) defines CR as a "(preferably) unique location ... where modules are composed". He argues for composing object graphs inside CR, near the application's entry point, and warns against the temptation to compose "classes a little at a time to create small subsystems".

An aggregate in DDD appears like such a subsystem -- a (sub) graph with entities and value objects. Evans (2004) and other DDD texts (Vernon 2013, Ghosh 2017) recommend constructing aggregates inside factories, located in the domain layer, "near" the aggregate (eg a factory method on the aggregate root) or as standalone services. This seems to contradict the CR approach.

The question is whether and how the CR and Factory approaches should be combined in DDD. For instance,

  • A CR is put inside the domain layer, rather than at the app's entry. Possibly, the factories are pooled to this single location
    OR
  • The benefits of CR (eg, the "ability to intercept subsystems to modify their behavior"; Seemann) are irrelevant to DDD.
  • CR DI does not apply to creation of aggregates but works at a higher granularity level (eg injection of services). Then CR methods use factories to construct aggregates, to place them on the object graph.

References
M. Seemann, 2012, "Dependency Injection in .NET"
E. Evans, 2004, "Domain-Driven Design"
V. Vernon, 2013, "Implementing Domain-Driven Design"
D. Ghosh, 2017, "Functional and Reactive Domain Modeling"

10
  • What is stopping you from having the aggregate factory be part of the object graph and thus making it possible that created aggregate is also part of the object graph.
    – Euphoric
    Feb 28, 2018 at 17:16
  • So we use static aggregate factories together with the DI and Composition Root? I thought DI replaces such factories. Also, do we put all these factories into one module/location? Feb 28, 2018 at 17:23
  • can you give an example of one of your aggregate factories? I'm not sure they would count as composition
    – Ewan
    Feb 28, 2018 at 17:26
  • @Ewan I don't immediately have a specific example, as I'm now figuring out the Evans' DDD book. Eg its Cargo Shipping example has Cargo as the Aggregate Root, with DeliveryHistory entity and DeliverySpecification value. Presumably, this (and any other) aggregate in DDD would be constructed in a Factory? So perhaps in general such factories should be used for small components, alongside higher-level DI from the Composition Root? Feb 28, 2018 at 18:09
  • Part of your problem might be that you're comparing a Composition Root with an Aggregate when you probably should be comparing it with an Aggregate Root. Feb 28, 2018 at 20:48

2 Answers 2

2

Typically, the composition root is about satisfying the dependencies of various modules that make up a process/application.

When Evans described DDD in the blue book, he was working in the context of a three tier architecture. You can think of the tiers as being modules - an application module, which knows about the interface(s) of the domain module but not the implementations, and a domain module that knows the interface of the persistence module, but not its implementation.

Because the coupling between modules is interface, rather than implementation, we can replace one module with another that implements the same interface, and it should all "just work".

The role of the composition root is the selection of implementations, and the wiring together of the dependency graph. So the composition root knows enough about the specific implementations to instantiate them, passing the appropriate implementation of each.

In architectures where constructor injection is favored, this might look like

PersistenceAPI persistence = new PersistenceModule(...)
DomainAPI domain = new DomainModule(persistence, ...)
Application app = new Application(domain, ...)

app.run()

Broadly, the modules describe their dependencies -- capabilities that they need but don't implement for themselves, and the composition root does the work of introducing capability consumers with capability producers.

An important thing to notice here; the pattern is deferring the binding of the consumer to a specific capability provider -- instead of forcing a choice when we build a module, we delay that choice until we build the root (or, with some additional work/assistance from DI frameworks, we can defer the choice until run time).

So for DDD, the answer is relatively simple: you use the composition root approach in those parts of your solution where you derive business value from deferring the binding of a consumer to a specific implementation.

Example: one way of persisting domain state is by writing data into an RDMBS, possibly with the help of an ORM. Another way would be to serialize that state into a document written to a document store. That might be a raw serialization of the object, or it might instead be in the form of a message/memento which is less coupled to a specific in memory representation.

Most of the app shouldn't need to care which of these choices that you make; so there can be business value in creating a seam that allows you to change this decision.

The composition root pattern gives you an element where the single responsibility is stitching these seams together into a working application.

7
  • OK, so the DI within the composition root is high-level, at the granularity of modules and layers. That makes sense. Could the composition root call factories to wire modules? Feb 28, 2018 at 21:03
  • @Tupolev._ It could. Does that approach best meet your specific requirements? Feb 28, 2018 at 21:25
  • @RobertHarvey I think so. It's also what I've been planning to do. I'm just confused by Seemann's advice in his DI book: "Do not compose classes a little at a time to create small subsystems" as it "limits ability to intercept those systems to modify their behavior". Does this imply there should be no object graph composition outside the composition root? Feb 28, 2018 at 21:35
  • It implies that you should compose the better part of your object graph in one place. Whether you do that in a single location for your application, or in multiple locations because you have pluggable modules, depends on your chosen architecture. But the object graph composition(s) should always be concentrated in central locations. DI containers are handy in large part because they provide you with the tools to do precisely that, in a highly-decoupled and organized way. Feb 28, 2018 at 21:37
  • Remember, before DI containers came along, people were simply newing up the objects that they needed locally, within the class. Then someone got the idea of handing those objects into the class via a constructor. Then someone else figured out that you didn't need to declare concrete implementations in the constructor; you could declare interfaces instead, which gives you the ability to swap out the implementation you hand to the constructor for a different one, provided it conformed to the same interface. Feb 28, 2018 at 21:43
0

This is how I'd approach the problem, based on the excellent answer and comments given.

There's a similarity between the Composition Root and an Aggregate Root: the former composes the whole application graph, and the latter contains the local object sub-graph for an Aggregate (@RobertHarvey). Hence, DI via a Composition Root can be used to compose program layers and modules within layers, and to swap interface implementations as required (@VoiceOfUnreason).

A factory "near" the Aggregate Root can be used at a finer granularity, to construct instances of a particular aggregate. Thus the knowledge is kept local eg, of how to construct value objects to populate the aggregate and how to validate it with specific rules. Also, for an aggregate representing a well-formed domain concept, no flexible implementations of internal members may be necessary. Still, a Composition Root DI may be used to inject aggregate factories into clients (@Euphoric).

In summary, I'd attempt a hierarchical approach, mixing higher-level DI from a Composition Root module with lower-level aggregate factories.

6
  • The last statement seems to be at odds with M Seemann's "Composition Root is a (preferably) unique location" recommendation and @RobertHarvey's comments. Is there a particular reason why you'd want an additional composition root for the domain? Mar 1, 2018 at 13:07
  • Also, I disagree with "[Aggregate Root composes] the local object sub-graph for an Aggregate". Usually it is an external object that composes it - a Repository, a Factory. An Aggregate Root may expand its Aggregate over time if it receives commands that spawn new entities or value objects, but I wouldn't wall that composition. Mar 1, 2018 at 13:11
  • I agree with both @guillaume31 comments and edited the post. Probably a better term is an Aggregate Root "combines" or "contains" a sub-graph. My main point is that it's preferable to construct aggregates locally at a factory. This seems to contradict M. Seemann's advice not "to compose classes a little at a time to create small subsystems" but do all composition at a Composition Root. Mar 1, 2018 at 13:31
  • I think what Seeman means by that is composing your graph by using the new keyword in your class constructors. Mar 1, 2018 at 14:12
  • Yes, and also, he's implicitly talking about the permanent applicative graph of objects that is known at startup time, not transient domain objects that may or may not be hydrated further down the road depending on user actions. Mar 1, 2018 at 14:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.