Understanding Bounded Contexts: Modularizing Software with Aggregates
Written on
Chapter 1: The Significance of Bounded Contexts
In the initial part of this series, I emphasized the critical role of Bounded Contexts in software system modeling. Understanding these contexts is essential, as they help delineate large domains into more digestible segments. Essentially, it's about identifying the various subdomains within a broader business domain, which subsequently allows for the recognition of Bounded Contexts. Each context establishes distinct boundaries around a subdomain, complete with its own unique model, language, and rules.
I deliberately focused on the concept of "verbs" to illustrate my point. This was intentional, as I've observed that many systems are constructed primarily around static elements, or "nouns," and later attempt to incorporate behavior. It’s crucial to keep in mind that both "nouns" and the "verbs" they perform are necessary for a comprehensive understanding of the software's functionality. Achieving a balance between the two is vital for effective software design.
> …both the nouns and verbs are required to fully describe behavior. Just as OOP is often misused, so is DDD. Both are important for building good software. Our profession seems to wander between extremes instead of seeking balance. — Dick Dowdell
Today, we will delve into another essential concept for modularization in Domain-Driven Design (DDD): Aggregates.
Section 1.1: Exploring Aggregates for Modularization
Once we have identified the Bounded Contexts, we essentially outline the modules that can be utilized to decompose a complex system into more manageable components. These modules can serve as foundational elements for transitioning a monolithic architecture into a series of modules, microservices, or autonomous systems. However, it's important to note that this initial identification may reveal that some contexts are indeed too large and require further subdivision.
Now, let’s transition to tactical design and approach the actual coding aspect. All the concepts we discuss will ultimately be translated into code. Our work is always conducted within a Bounded Context, which could represent a module in a monolith or a microservice. DDD introduces various tactical design patterns, including factories, repositories, value objects, entities, and Aggregates. For this discussion, we will concentrate on value objects, entities, and Aggregates, as they are crucial for enhancing modularity.
Subsection 1.1.1: Understanding Entities and Value Objects
Entities are pivotal in DDD because they consistently retain their identity and behavior, along with their distinct life cycle. Each entity is characterized by its unique identity, which sets it apart from others, even if they share identical attributes such as name, age, or occupation. For instance, two individuals may have the same name, age, and job title, but their unique identities are what truly differentiate them.
It's essential to clarify that entities in DDD are not mere data models (i.e., representations of database tables); rather, they are domain models. They encapsulate business objects along with their behaviors, focusing on domain concerns rather than database structures.
Conversely, value objects are defined differently. They lack a unique identity and do not possess a life cycle. Their essence is derived solely from their attributes, and they are always immutable.
Section 1.2: The Role of Aggregates in DDD
Aggregates serve as an effective means to prevent the complexity of large object graphs within a Bounded Context, which might arise if we relied solely on value objects and entities. By using Aggregates, we can group value objects and entities together while establishing a defined boundary.
Without Aggregates, the arrangement of our objects could quickly become unwieldy and difficult to manage, increasing the risk of errors. We want to avoid situations where changes in one area inadvertently cause issues elsewhere.
As mentioned earlier, we group entities and value objects into what is referred to as an Aggregate. Each Aggregate is anchored by a central component known as the root entity, or Aggregate root. This root serves as the sole entry point to the Aggregate, possessing a unique global identity and overseeing the enforcement of invariants.
Invariants are the rules or conditions that must remain true for the Aggregate to be deemed valid. These could range from ensuring an account balance never falls below zero to verifying that an order contains at least one item before processing. The Aggregate root is responsible for enforcing these invariants, maintaining the integrity and consistency of the Aggregate's state. Thus, any modifications made within the Aggregate’s boundaries must satisfy all invariants. You can think of the Aggregate as a boundary for transactions.
In the example presented in Eric Evans' book "Domain-Driven Design," the Aggregate regulates access to the associated objects solely through the Aggregate root. Other modules are prohibited from directly interacting with the Tire entity, a rule established to preserve system-wide consistency. It's vital to understand that external entities cannot hold references to elements within the Aggregate, such as the Tire. While the root can share a copy of a value object with another entity, it does not track the subsequent actions related to that copy. Since the copy is merely a value without ongoing ties to the Aggregate, its status outside the Aggregate becomes irrelevant.
Aggregates are designed to remain independent of each other; they function as isolated units. They act as a facade, concealing their internal mechanics and specific business logic from external interactions. However, it is permissible for one Aggregate to reference the unique ID of another Aggregate's root.
Cheers!
PS: If you're interested in discussing this article or exploring other DDD-related topics, feel free to join my new Discord server!
Chapter 2: Learning More Through Video Resources
To enhance your understanding of Bounded Contexts, I recommend the following videos:
The first video, "Dissecting Bounded Contexts - Nick Tune - DDD Europe 2020," provides an in-depth exploration of Bounded Contexts in the realm of DDD.
The second video, "[DDDDD-20] Bounded Contexts, Microservices, and Everything In Between," further discusses the interrelations of Bounded Contexts and microservices.