I have been struggling with many aspects of OO development over last couple of years, all in an effort to improve my software. I have, along with others, been trapped in the DDD Aggregate Root thinking that appears to be everywhere. It appears as though there is this opinion that ARs are the centre of the universe and I have come to the conclusion that it must have something to do with the consistency boundary afforded by an AR. This seems to have become the central theme. Almost as though it became necessary to define DDD in some structural sense.
So, all-in-all, the idea that an the AR changes from use-case to use-case is not true. The consistency boundary does, however, change. What contributed to my thinking seems to be the fact that everyone thinks that the only object that may be loaded by a Repository is an AR. This too is a fallacy.
Any entity may be loaded from a Repository.
So what is an Aggregate Root?
The aggregate concept is not new. The classic Order->OrderLine example comes to mind. An OrderLine has no reason to exist without it's Order. However, people tend to confuse ownership with aggregation. I know I have. One may manipulate an Order directly, even though it belongs to a Customer. One would never manipulate an OrderLine directly. So an AR boils down to how you manipulate your objects. The consistency is a side effect since an AR only makes sense as a whole in the same way a class only makes sense as a whole. Both should remain consistent.
So to manipulate an aggregate we nominate an entity within the aggregate to represent the aggregate. This becomes the Aggregate Root.
But in many, if not most, cases this entity is only the representative. Using Eric Evans' example in his 'What I learned...' presentation: an aggregate consisting of a Stem and a collection of Grape objects may have, as the root, the Stem class. But this does not really represent the GrapeBunch aggregate properly. In some instances one may probably want a GrapeBunch class and use composition to get to the aggregate. Mr. Evans mentions that he has no real issue with doing this. However, I feel too many aggregates end up as abstract concepts in the domain. It may be that the defined Ubiquitous Language has missed the concept or that the domain experts even missed the aggregation themselves.
Aneamic Use-Case Model
It is my opinion that use-cases (or user stories, or whatever you want to call them) may not receive the necessary attention in our modelling. Well, mine anyway. I have been using a 'Tasks' layer but have been trying to move these into my entities and ARs. This may have been a mistake.
I will be mentioning bits from the use case and sequence diagram Wikipedia articles.
Firstly, we need to see where a use-case fits in. There are essentially two kinds of 'workflows' in any system: sequential and a state-machine.
Now looking at what a sequence diagram does:
"A sequence diagram shows, as parallel vertical lines ("lifelines"), different processes or objects that live simultaneously, and, as horizontal arrows, the messages exchanged between them, in the order in which they occur. This allows the specification of simple runtime scenarios in a graphical manner."
And what a use-case is:
- "Each use case focuses on describing how to achieve a goal or task."
- "Use cases should not be confused with the features of the system under consideration."
- "A use case defines the interactions between external actors and the system under consideration to accomplish a goal."
A use-case appears to fit the idea of a sequential workflow. It is completed in one step. So we can call it an operation. This operation takes place in response to a command from an actor in the system. If may then publish an event. These operations resemble transaction script [PoEAA] and may be why some folks choose to stay away from them since it is confused with an aneamic domain model. However, they are, in sooth, operation script (also Fowler). Now, I have been defining a 'Task' for my operations but since moving to DDD-thinking I have been trying to move these into my domain classes. It isn't working. I feel that use-cases need to be made explicit also. They lie in-between task-based domain interaction and state-machines. The other thing is that one operation may need to interact with another.
The term workflow is most often associated with a state machine. The finite state machine article on Wikipedia may be referenced for more information.
Workflow does not fit into the typical use-case definition and it is probably the reason why the term process is used quite often in business requirements documentation.
What I find interesting is that in any business domain of reasonable complexity one will find all these concepts hidden away. Developing a computer-based solution that takes all of these factors into consideration is a monumental effort and in many cases is under-estimated. What I have seen over the years appears to be a tendency to focus on specific technologies to try overcome this intricate mass. Software such as BizTalk has been abused.
At the root of everything, though, is data. We need data to represent the real world state. This leads to a group of developers relying only on data manipulation to perform all these specialized areas. But everything is built up from the data, so (bold is good):
- Data Structures
- Data Manipulation (Procedural Code / Transaction Script)
- Behaviour (OO Code)
- Entity-Based Interaction
- Task-Based Interaction
- Use-Case Modeling (Operation Script)
- State Machines (Workflow / Saga)
And to top it all off we will add Service-Orientation. SOA would wrap all of these.