Which is the best way to separate aggregate in DDD

1.3k Views Asked by At

I'm learning about DDD, I don't clear about how to separate objects into aggregate.

An example:

I have 3 objects: company, shop, job.

And i have some relationships: one company has many shops and one shop has many jobs.

I thinks:

A shop can't exist without company. And a company have to has shops, it's real world. So that, i group company and shop into one aggregate.

Job is another aggregate.

Another thought

When getting a job, i always care about which shop this job belongs to. So that, i group: shop and job into one aggregate.

Company is another aggregate.

Which way is right?

Thanks

1

There are 1 best solutions below

0
On

The only possible answer is, of course, "It depends." That's not especially helpful, though.

Review the definition of an aggregate from Evan's book:

An AGGREGATE is a cluster of associated objects that we treat as a unit for the purpose of data changes ... Invariants, which are consistency rules that must be maintained whenever data changes, will involve relationships between members of the AGGREGATE. Any rule that spans AGGREGATES will not be expected to be up-to-date at all times ... But the invariants applied within an AGGREGATE will be enforced with the completion of each transaction.

So the questions of "what objects make up my aggregate" and "what is my aggregate root?" depend on what business invariants need to be enforced across which business transactions?

You do not design aggregates likes you do tables in a relational database. You're not concerned about the multiplicity of the relationship between the entities in "real life". You're looking for what facts (properties, values) must be true at the end of an action that affects (mutates the data of) those entities.

Look at your requirements. Look at what kinds of behavior your system needs to support. What can you do with jobs? Create them? Start them? Complete them? Can you transfer a job from one shop to another? Can a job move between companies?

What facts need to stay consistent? e.g., are you enforcing a maximum number of jobs per shop? At the end of "adding a job", does the current # of jobs in a shop need to be consistent with the job's shop assignment?

Since you can only interact with an aggregate through its root, you need to think about the context of how you add new data. e.g., can you create a job with no initial shop assignment? Or can it only be created through a shop?

There's also a compromise between the size/scope of an aggregate and the possibility of data contention when updating an aggregate in a transaction.

With all of these things to worry about, you may wonder why even bother with aggregates? Well, they are great at a couple of things:

  • validation and execution of commands is FAST, because all the data you need is self-contained inside the aggregate
  • they lend themselves well to document-based persistence stores (like MongoDB with nested documents for the aggregate objects), which makes retrieval of the aggregate state simple and performant, and enforcement of the aggregate transaction boundary easy with document-level atomic updates
  • they are extremely easy to test, because they can be implemented as simple classes (POCO's/POJO's in C# or Java). Because they contain the majority of your business logic, it means your overall app's behavior is easy to unit test as well!
  • they are intentful; each aggregate has a purpose, and it's very clear from the data and functions they implement just what they do in your system. Combined with leveraging the ubiquitous language of the context you're coding in in the code itself, they are the most direct expressions of your business behavior in the codebase (much more so than a set of data tables alone)
  • because they are so use-case specific, aggregates often avoid leaky abstractions that crop up in more generic solutions

If you're interested in reading more, Vaughn Vernon has a nice summary in his Effective Aggregate Design posts, which served as the basis for his meaty book "Implementing Domain-Driven Design".