Search code examples
architecturemicroservicesdomain-driven-design

In domain driven design, should an aggregate keeps redundant or aggregated data from another aggregate to maintain invariants?


In domain driven design, should an aggregate keeps redundant data from another aggregate to maintain invariants?

For example, if we are designing a system with School and Student aggregate roots, there is a business rule: the total number of students in a school must not exceed 1000

There are two ways to enforce the rule when enrolling a new student to a school:

  1. do a select count from Student and check the number against 1000, might need to lock by school id

  2. maintain "student_count" property in School aggregate, validate the constraint inside the School domain, increment student_count first, then create a new Student. Need to update "student_count" property when students are deleted(left school or graduated).

Actually I prefer approach 2 as it enforces invariants of School domain, but my colleagues argue that approach 1 is simple to write and maintain.

I am looking for more discussions on this subject. Thanks


Solution

  • For example, if we are designing a system with School and Student aggregate roots, there is a business rule: the total number of students in a school must not exceed 1000

    The general term for this problem is set-validation.

    If "must not exceed 1000" is a hard constraint (like: if this ever happens lives will be lost / we can get sued out of existence), then the answer is that the set itself must be completely contained under a single lock, which usually translates to "the set must be completely contained within one aggregate".

    So that might mean that the "school" aggregate includes a set of student ids, and that when that set includes 1000 ids then enrollment is closed.

    It's much more common that set constraints are soft ("when this happens we make less money"), in which case we can use discrepancy reports and escalation to trigger the domain processes that bring the set back into compliance.


    There's been discussion recently on slack:ddd-cqrs-es about the fact that the constraints we use for "scheduling and planning" are often stricter than the constraints we use for "operations".

    One key difference to recognize is this: when operating in the real world, the real world is the "book of record", our model is just working from a locally cached copy of information that may be wrong or out of date. We have to be cautious about designs that prevent the real world from correcting our data.