View More

Organizing our software into modules and contexts helps us going a long way toward clean and maintainable systems. Domain-Driven Design (DDD) describes some additional concepts or practices that go even further to organize code artifacts with standardized methods.

DDD’s large scale structure is comparable to classic software architecture. The big difference is that many traditional approaches are concerned with technical concepts like views, controllers, or data access. Large scale structure attempts to organize code according to domain concepts instead.

System metaphor

The first (and well-known) concept Eric Evans describes in his original book [Eva04] about DDD is the system metaphor. The idea to find an overarching metaphor for whole software systems isn’t new though. Extreme Programming describes it prominently as a way for shared understanding.

In DDD, the metaphor is also used to organize code on a larger scale. For example, we may discover that the system we build in the domain of some scientific calculations lends itself to the metaphor of a blackboard. There is data written to the board. Experts are standing in front of it, calculate new values, and write them on the board. With this metaphor, we can organize the code according to its concepts.

Metaphors can be inexact through. Therefore we should always ensure that it doesn’t get into the way of a design that does better resemble our domain.

Responsibility Layers

We all know about layers in software. They help us divide components into different parts that have distinct (technical) responsibilities. In DDD, we try to layer the domain in addition to technical duties according to domain responsibilities.

For example, in the domain of an inventory system, there could be an infrastructure layer that contains storage locations with their capacities. For the products that can be stored, there is another layer which resides below the infrastructure layer. With such layering in place, the organization of code becomes even more apparent. Like with the technical layers, we should take care of the dependencies. Always depend on lower or inner layers and never allow cyclic dependencies.

Knowledge Level

In some domains, we may be able to divide the code into a knowledge level and a supporting worker or implementation level. The knowledge level describes what the software wants to achieve. For example, a domain-specific language (DSL) is a kind of knowledge level.

The worker or implementation level is then responsible for interpreting what the knowledge level describes and execute functionality accordingly. A prominent example from daily life is query languages. We state what we would like to query only but not how. The how is in the responsibility of some implementation that executes our query.

Pluggable Component Framework

The most rigid and limiting pattern of strategic design is the pluggable component framework. One way to implement it would be to define an abstract core. This core defines the interfaces of plugins that would like to contribute to a bigger process. That process may too has multiple implementations for which the abstract core defines the abstractions and interfaces.

Now we are free to combine different plugins into different applications. While this composition is very flexible and enables reuse of the plugins, the structure is stive and cannot be changed easily.

Wrap Up / Final Thoughts

The large scale structure part of DDD contains some interesting concepts. They focus on organizing code to improve the understandability of a system. I think if we implement one or more of these concepts while building our software, we can improve many aspects of the process.

New team members, as well as ourselves, profit from a big picture of the system. Modules are organized well according to their responsibility. The large scale structure should also be understandable by non-technical people and therefore helps us to improve communication with them.

[Eva04] Eric Evans: Domain-Driven Design – Tackling Complexity in the Heart of Software (homepage)

View More

If we start building software with domain-driven design (DDD), it can seem to be much work to model everything. Luckily, any domain of reasonable size has sub-domains of lesser importance. However, how do we separate these from the essential concepts? Where do we invest in DDD if resources are limited?

These questions may be answered with the chapters about the distillation of the core domain of Eric Evans’s DDD [Eva04]. This core domain is the part of our application that we want to be of the highest quality as possible. Domain Vision Statement, Highlighted Core, Cohesive Mechanism, Segregated Core, and Abstract Core are concepts that we can use to distill the core domain.

Different domains

Not every part of a given application is equally important. There are (sub-)domains that are used by many businesses. For example, accounting or project planing are domains that are needed by most companies. These are called supporting domains in DDD.

The core domain, on the other hand, is concerned with the unique selling point of our business. The company values that part of the domain the most. That’s why we want it to be of the highest quality as possible. It is the part that justifies the initial effort that DDD may require.

Last but not least, there are generic (sub)-domains. These parts of our domain are well known and used in many applications. More often than not, there are standard solutions or libraries available that we can use. We don’t even need to develop them ourselves but integrate them as a bounded context.

Domain Vision Statement

The first and easiest option to distill our core domain is to write a Domain Vision Statement. Typically this will be one page with a very high-level definition of the core domain. It should only consist of domain-specific language and not be concerned with technical things like availability.

The domain vision statement can act as a lightning post where team members refer to in the early stages of a project to decide about the placement of artifacts and naming. Alternatively, if there is legacy involved, the domain vision helps to identify the first parts of the domain that we want to attack with refactorings.

Highlighted Core

The next stage, when distilling the core, could be to highlight it. In a greenfield project, we could write a brief document of some pages that describes core components and their interactions. The text should still be as concise as possible to prevent it from becoming out of sync with the development.

In projects with much formal specification, it could be useful to compile the relevant parts in one place. Highlight the core by pointing to existing specifications that deal with the most valuable concepts.

When highlighting the core, team members can reason and communicate about it. While doing so, the distillation continues, and it becomes clearer what the core is and what we may refactor as sub-domain.

Cohesive Mechanism

Sometimes when we are refactoring our domain model, a cohesive mechanism emerges. It could be a concept or pattern that is general knowledge in software development like graph operations or something like a rule engine.

The cohesive mechanism should be factored out of the core domain and put into a supporting module. This simplifies the core domain, and most developers can understand the cohesive mechanism or look it up at least.

In contrast to generic sub-domains which subtract a part of the core domain, cohesive mechanisms can be used to encapsulate complex logic. Both patterns leave behind a more coherent and simplified core domain.

Segregated Core

When there are multiple concepts entangled within the core domain, we may want to create a segregated core. Inside the core, we focus sharply on the core domain. We refactor all supporting concepts into classes in separated modules.

While it can be beneficial to reduce the size of the core in this way, we should always keep an eye on the dependencies that are needed. If the core module(s) and supporting modules would have to have many dependencies after the refactoring, it may be better if the concepts stay within the core.

Abstract Core

Another way to reduce the size of a core could sometimes be to create an abstract core. If there are distinct areas of the core that use a common subset of it, we can refactor those functions into an abstract core. Most dependencies between those areas are located within the core. The specialized sub-domains depend on the abstract core and won’t have dependencies between each other.

Wrap Up / Final Thoughts

The distillation of the core is about focus and cohesion. Focus on the most valuable part of your software and make it cohesive. That way, we can reduce overhead and allocate our resources most efficiently.

Evans didn’t mention it explicitly as far as I know. But I think the core domain is what he refers to with the title of his book about DDD: “Tackling Complexity in the Heart of Software”. Therefore it’s not only for the business essential to focus on the core domain but also for us as software engineers.

[Eva04] Eric Evans: Domain-Driven Design – Tackling Complexity in the Heart of Software (homepage)

View More

Let’s continue to look at the supple design patterns of domain-driven design (DDD). Previously we learned about Intention-Revealing Interfaces, Side-Effect-Free Functions, and Assertions. These patterns help greatly reduce mental overload and should lead to a supple design without surprises.

In this post, I would like to cover Conceptual Contours, Standalone Classes, Closure of Operations, and Declarative Style of Design. One overarching theme of these is coupling and cohesion. They help us reduce coupling and increase cohesion, which can have multiple benefits.

Conceptual Contours

When we design and create our objects and classes, we should always keep the concepts that they represent in mind. Sometimes after coding for some time, I like to stop and take a look at what I’ve created. Is the code still in line with my original concept? Should I refactor some interface? Or is my understanding now different than when I started?

These are the moments where conceptual contours emerge. I think that most of the time we don’t get these right in the first place. Only through continuous refactoring, we eventually arrive at a point where there is the right amount of coupling and cohesion.

The benefits we get when we take the time to refactor towards these conceptual contours are readability and maybe even reusability. If the components we created have low coupling and high cohesion, there should be a higher probability that they can be reused for another feature or story.

Standalone Classes

With Standalone Classes, we have no coupling at all. You may think that this is impossible. There always has to be some coupling. Otherwise, the class cannot be useful. However, more often than not, we can reduce the coupling to the most primitive types in a language, for example.

Let’s take a look at an example in the domain of a webshop. Prices of products are calculated by applying a discount on a default price based on various conditions. We could implement this requirement in various ways. Let us first consider the following possibility:

This design can be reasonable because it’s easy to use by clients, and the base price is encapsulated within the product. If we like to focus on low coupling instead, we could come up with this design:

As you can see the dependency is gone and we have two standalone classes (If you think of Amount as a base type not counted for coupling). The advantage of this design is that we can test both classes in isolation now.

Closure of Operation

Closure of operations is a concept from mathematics. It states that a set is closed under an operation if the execution of that operation on members of the set always produces a member of that same set. Such operations have only arguments and return values of the same type.

Besides mathematics, there are some other domains where we could apply closure of operation like metallurgy, atmosphere, or color (the original sample in Eric Evans book on DDD [Eva04]).

Declarative Style of Design

The basic definition of the declarative style of design (or just declarative programming) is: Describe what you want to accomplish instead of how. Most of the time, there needs to exist an abstraction layer that implements how below the layer with the definition of what.

Now you already can imagine a drawback of declarative style. The effort to build something that executes your model can be very high. However, there are advantages too, of course.

The declarative style could be seen as the ultimate supple design. If we design our own domain-specific languages (DSL) for example, the design becomes ultimately supple. Working in the declarative model layer becomes simple and intuitive.

Wrap Up / Final Thoughts

Low coupling and high cohesion are worthwhile goals of software development stated by many mentors of our profession. The patterns in this post provide some guidance on how to achieve those properties with a supple design.

I especially like the idea of DSL. We built one at opus software for our measurement system, and it turned out to work pretty well. However, I understand that not every system can profit from a specific DSL.

[Eva04] Eric Evans: Domain-Driven Design – Tackling Complexity in the Heart of Software (homepage)

View More

Today I would like to introduce the concept of supple design. Previously through this series about domain-driven design (DDD), we climbed up the abstraction hierarchy from class level patterns up to the context map. With supple design, we are back on the class or function level. Some synonyms of supple are agile, flexible, or bendable but also smooth. Supple design is obvious, doesn’t obscure things.

Let’s split the concepts of supple design up into two parts. This first post is about Intention-Revealing Interfaces, Side-Effect-Free Functions, and Assertions. Next time I will introduce Conceptual Contours, Standalone Classes, Closure of Operations, and Declarative Style of Design.

Intention-Revealing Interfaces

As you may have heard before and experienced yourself, the complexity we humans can handle well is limited. Software design acknowledges this. Concepts like information hiding and abstractions have been invented by smart people long ago.

However, these concepts are only useful if we don’t need to know the details of abstraction, for example. We need to design our interfaces in a way that reveals their intentions to their users. Callers shouldn’t need to check the implementation to understand what an interface method does. If the intention is clear cognitive load is lowered, and they are able to think about other things than our (maybe perfectly crafted) implementation.

For example, take a look at the following interface of a class that stores a user-to-terminal mapping.

How do you remove a mapping with this interface? Experience or intuition may tell you that we need to call the setUserForTerminal method with null as the argument for terminal. Nevertheless, we cannot be sure without looking at the implementation. Maybe mappings expire after some time, or the author of the interface forgot about the case when we need to remove a mapping.

A solution could be that we add another method that removes the mapping like this.

Side-Effect-Free Functions

The concept of Side-Effect-Free Functions has become widely known through the past ten or fifteen years with functional programming. It has various benefits if we know that a function doesn’t change any observable state of the system.

DDD separates queries and commands strictly, which takes us a long way towards a supple design with side-effect-free functions. Another technique that Eric Evans describes in the original DDD book (Eva04) is to extract a value object. Value Objects are immutable by definition. Therefore all of their methods need to be queries. If we can replace a change of state with the creation of a new value object, it should become simpler to reason about the design.

For example, let suppose we have an invoicing module where we can add discounts on individual invoice items. The implementation is a method applyDiscount(Amount amount) which adjusts the item’s amount by the given value.

Now we introduce a new value object called Discount. The applyDiscount(Discount discount) method puts the given discount object on an internal list on the invoice item. When asked for its amount the item uses the list of discounts to calculate the value on demand. The state of the invoice item is never changed. It becomes a value object.

Assertions

Assertions are again a very widely known concept. In some languages, they are supported as a language construct. In others, we can use tests to check them. Assertions define pre- and postconditions of method executions. We can define assertions on method arguments, for example, and also on the internal state of an entity which is especially useful as postconditions.

When we define assertions for our methods, we improve the correctness of our software by disallowing invalid state to propagate. Assertions serve a documentary purpose. Reading a test, that states assertions about the methods of a class, is often more straightforward to understand than the implementation.

Vaughn Vernon discusses assertions in some detail in his book “Implementing Domain-Driven Design” [Ver13] while describing different levels of validation. The first is the attribute level and can be executed when an attribute is set to a new value. The second level is the validation of a whole object. Just because every single attribute of an object is valid doesn’t mean that the whole object is also valid. Therefore we check the validity of different attributes in relation the others. This validation can be invoked internally at the beginning or end of method execution or from the outside. The third level of validation orchestrates assertions of multiple objects on an aggregate, for example.

Wrap Up / Final Thoughts

Supple design is one of my favorite areas in DDD because it addresses multiple concerns. The first is readability: When we write code with great care to these practices, it is a pleasure to read it afterward.

Another one is correctness. When the intention is clear, our interface is more likely to be used correctly. If there are no side-effects bugs are less likely to occur. Validations help to prove the correctness of our code at runtime.

[Eva04] Eric Evans: Domain-Driven Design – Tackling Complexity in the Heart of Software (homepage)
[Ver13] Vaughn Vernon – Implementing Domain-Driven Design (homepage)

View More

Different areas or parts of a software system are called bounded contexts in domain driven design (DDD). In the previous post of this series I tried to explain what the properties of these bounded contexts are. Now software systems very seldom consist of only one isolated context. Either the software itself is big enough to be split into multiple ones, or it is interacting with outside systems through API’s. In either case, the context map helps to understand the system by showing the involved contexts and their connections.

We can connect multiple contexts in many ways and model different relationships between them. In DDD these are explicitly named and defined patterns called integration patterns.

Context Map

Let’s first look at a context map example. The following map shows the bounded contexts from the example application also used in my previous post: Billing and Marketing. However, this time I added important detail, the name of the relation between the two contexts.

For this example, I choose the customer/supplier integration pattern. Therefore the billing context (supplier) needs to provide means for the marketing context (customer) to access required data or functions. When we clearly define and communicate these relations with a context map, we provide guidelines on how the contexts need to interact with each other.

How to start

If we work on a greenfield project we start developing the ideal context map according to our current knowledge. But if there is an existing system that we would like to improve, do we start with the ideal situation too? Eric Evans states in his original book about DDD [Eva04] to start with a context map of the current situation. Afterward, we can identify areas we like to improve and derive context maps accordingly.

That’s very practical advice because it is much simpler to improve a certain area of the software than to draw a bright picture of the future that is very difficult to achieve in one step.

Integration Patterns

Here is the list of DDD integration patterns in no particular order: Customer/Supplier, Shared Kernel, Open Host Service, Published Language, Anticorruption Layer, Conformist and Separate Ways.

The integration patterns can be aligned on two axes. The first is how good the involved teams communicate and adhere to the commitments they make. The second is how much control you have over the involved systems. When deciding on which pattern to use it is helpful to keep these in mind. The following introductions to the different patterns include a hint on where the pattern is located on the axes.

Customer/Supplier

In the customer/supplier pattern, as the name implies, one context is the supplier of data or functions to the other. In planning sessions, the teams act according to their role, negotiate deliverables and schedule.

Because the supplier implements functionality the customer needs, the same rules apply as for an external customer to the business. The customer needs to be available for questions the supplier team may have.

On the other hand, the customer is king. Their needs do have to have priority for the supplier team. Otherwise, the customer team may be blocked and cannot continue to deliver value to the company.

Level of communication and commitment: Medium
Level of control over the involved systems: Medium

Shared Kernel

When two contexts seem to have a common set of entities they may want to use a shared kernel. Both teams need to be willing to cooperate with and regard each other’s needs.

A shared kernel should include both model and data persistence. It should be automatically tested on each change with suites from both teams to ensure compatibility.

With the shared kernel duplication can be reduced and we can easily integrate contexts. However, big commitment is needed from the teams because they cannot change the kernel freely.

Level of communication and commitment: High
Level of control over the involved systems: High

Open Host Service

When we need to integrate a bounded context with many others, it can be useful to build a common model for all integrations. This model is published as a set of services that the other contexts use.

It is only feasible to implement an open host service when we can find a common model, and the other contexts are willing to accept it. Of course, each consuming context can build an anti-corruption layer on his end, but this defeats the use of the open host service somewhat.

Level of communication and commitment: High
Level of control over the involved systems: Medium

Published Language

Further development of the open host service may lead to (the use of) a published language that has it’s own bounded context. The language could be a model defined by some industry association or state for example.

As source context, we may translate into the published language and out of it if our model doesn’t match. We provide our services in the published language.

Level of communication and commitment: High
Level of control over the involved systems: Low

Conformist

With the conformist integration pattern, we adapt our model fully to the model of the other context we would like to connect. There are two reasons why it may is a good idea to be a conformist.

The first is if the translation from and to the other model would be very complex. It could be complex because we have no control over the other context for example. Alternatively, it is a very different context that is naturally difficult to translate into our own.

The second reason is if the other context is based on a common standard or component. Most probably the model of this context is very mature in its area. Your model may didn’t get this far yet.

Level of communication and commitment: Low
Level of control over the involved systems: Low

Anticorruption Layer

If we have no control over the context we would like to connect to, and its model doesn’t fit ourselves an anticorruption layer should be considered. This layer communicates with the other context in its language and translates from and to it.

The anticorruption layer can be especially useful when migrating a legacy system. It encapsulates the legacy system, and our new shiny solution communicates only with this layer in a clean language.

Level of communication and commitment: Low
Level of control over the involved systems: Low

Separate Ways

Because integration always has an associated cost you may want to go separate ways instead. Maybe you rather duplicate some logic and data in your own context than build a complex integration layer.

The two contexts may still be connected through a middleware tire or on the GUI level. However, take care not to connect them on a model level accidentally.

Level of communication and commitment: Low
Level of control over the involved systems: Low

Wrap Up / Final Thoughts

I think the benefit of context mapping is very obvious. It is beneficial for teams if they know their relationship to other parts of the software system they build.

Maybe the integrations between different contexts don’t always follow exactly one of the patterns. I think they can be altered or even combined at times.

[Eva04] Eric Evans: Domain-Driven Design – Tackling Complexity in the Heart of Software (homepage)

View More

The next parts of this series about domain driven design (DDD) will be about bounded contexts, how to keep their integrity and integrate them with each other. In this post, I would like to introduce the bounded context pattern.

When modeling a domain, it is important to define a common language for it. In DDD this is called the ubiquitous language. Every term in the ubiquitous language has a well defined, unique meaning within the boundaries of the (sub)-system under design. This boundary is called “bounded context”.

Why

When we start designing our software from a database-centric view, we tend to build big database entities that contain all possible attributes. We use these entities in multiple features of the software. For example, we use the customer entity in the context of billing as well as marketing. It is easy to build such big entities, but they tend to be hard to use.

In DDD we design two different bounded contexts for billing and marketing. Customers are represented differently in each context, have different attributes and functionality. The advantage of this approach is simpler entities with fewer attributes and functionality which also leads to fewer concurrency issues.

A drawback is the need to synchronize contexts which may be complex to achieve. For example, the billing and marketing contexts would like to share customer information. There are multiple solutions for synchronization available both from DDD itself in the form of integration patterns as well as related techniques such as event sourcing and eventual consistency.

Example

The following diagram shows the customer entity in the bounded contexts of billing and marketing.

As you can see the customer entity needs very different attributes depending on the context. Marketing wouldn’t care about open invoices probably. Moreover, billing needs only one communication channel, the billing address.

Organization

A single team should be assigned to develop a bounded context. When multiple teams work together on one bounded context, it is difficult to keep the ubiquitous language clean. Also, we can prevent very big bounded contexts with this rule. When one team doesn’t seem to be enough to build a bounded context, it is maybe too big, and we should split it into two specific ones.

On the other hand, one team may very well develop multiple bounded contexts. Many domain models have different meanings and language depending on the context. It can be useful to split the system into two contexts even if the same team maintains them.

Continuous Integration

Even when only a single team works on a bounded context, it is possible that different views of the model exist within team members. To address those and keep a unified understanding of the model and its ubiquitous language, DDD encourages the use of continuous integration.

The term “continuous integration” is used nowadays mainly in the context of DevOps, meaning to merge, build and test the code continuously. When using  DDD, we also discuss the domain and ubiquitous language regularly. Frequent interaction between team members ensures that every code is written in sync with the model and no sub-contexts emerge with a separate language accidentally.

Wrap Up / Final Thoughts

Bounded contexts organize model elements on the level of domain boundaries. They help us understand that one concept can have very different meanings depending on the context. If we are aware of the contexts that exist in our software system, we can prevent misunderstandings and therefore build the right thing.

Implementing the same concept in different contexts comes at the cost of synchronization through. Therefore these contexts should have a reasonable size to prevent this overhead.

The next post will be about how to model and connect multiple bounded contexts. The model integration patterns that DDD provides offer many different possibilities.

View More

Two more concepts which are important patterns of tactical modeling in domain driven design (DDD) are Aggregates and Modules. Both aim to organize the other building blocks of the domain model. Aggregates group multiple Entities and Value Objects together into one cohesive unit. This unit is also the transactional boundary within which we can guarantee certain invariants.

Modules are used to organize the elements of a domain model on an even higher level than aggregates. They provide a different, higher-level view on the model and code where details are hidden. Without those details in the way, cognitive load is reduced and we can reason about connections between groups of domain elements.

The Aggregate Pattern

Aggregates group together entities and value objects into a cohesive unit. The main entity of the aggregate is called an aggregate root. Clients are not allowed to access the other elements of the aggregate directly but only through the root entity. In other words, the root is the API of the aggregate.

Each aggregate denotes a transactional boundary. Within this boundary, we can guarantee certain invariants with validation logic. After every command or a series of commands that we execute on a single aggregate, we validate the state and commit the changes.

Because aggregates form the transactional boundary only objects that need to be absolutely consistent with each other should be in the same aggregate. Generally speaking, they should be kept as small as possible. Maybe we could start with one aggregate per entity. Later when we talk with the domain experts about consistency, a requirement could be discovered to combine multiple entities into one aggregate that can guarantee consistency constraints.

Sample Aggregate

Let’s look at the example of a customer relationship management (CRM) application. One requirement of the CRM is to store customer contacts. Each contact can be reached by multiple communication channels. We already decided that contacts are modeled as an entity because they need an identity. We model communication channels as value objects that don’t need a lifecycle. These two objects naturally form an aggregate where the contact entity is the root.


If we would like to create a new communication channel the classical way would be to create one and associate it with the contact. We would need to know the concrete implementation of the communication channel and how to associate it with the contact.

With the contact aggregate, we are not allowed to manipulate communication channels directly. We ask the contacts aggregate to add a new channel with primitives as parameters. We use the API of the aggregate which is free on how to create the communication channel and link it to the contact.

The Module Pattern

The domain module is a container for the other domain objects. It groups them into highly cohesive units. Objects within the module should be closely related to the domain concept it describes. Between modules, we aim for low coupling to reduce the mental load when working with its elements. By naming the modules according to the ubiquitous language, we can tell the story of the system on a higher level.

The following diagram shows a module of the CRM application. There are many other possible ways to form modules of a CRM through depending on the context and background of the domain.


In the original DDD book [Eva04] Eric Evans described modules as a way to group domain objects on the level of packages or namespaces. Nowadays many languages have a notion of module above the package or namespace structure. Therefore we have more flexibility when designing modules. We can use packages or namespaces to group objects very fine granularly and use the module language construct to model the domain modules.

On an even higher level modules are organized in bounded contexts which is the first strategic modeling pattern that I would like to introduce in the next post. When the bounded context is relatively small and contains only a few aggregates we maybe not need to split them into modules. However, in bigger contexts, they help to further divide the domain into units that we can work with.

Wrap Up / Final Thoughts

The aggregate pattern addresses some common pain points that are widely known and which I observed too in some applications. One is the overuse of getters and setters to change data that is multiple relations away. Aggregates prevent this by only allowing access to the aggregate root and restrict access to the other objects. Another point is the transactional boundary they provide. It prevents transactions over many objects which could lead to poor performance or even deadlocks.

Modules are a concept that I like very much since I first learned about them through Kirk Knoernschield’s book “Java Application Architecture” [Kno12]. They are very helpful In organizing code on a relatively high level. I’m looking forward to modularizing a domain model.

[Eva04] Eric Evans: Domain-Driven Design – Tackling Complexity in the Heart of Software (homepage)

[Kno12] K. Knoernschield: Java Application Architecture – Modularity Patterns with Examples Using OSGi (homepage)

View More

In the previous posts of this series about domain driven design (DDD) concepts and patterns, I introduced some of the building blocks of a domain model: Entities, Value Objects, and Factories. Today I would like to extend this list with the Service and Repository Patterns.

(Domain) Services are stateless objects that contain logic which cannot reasonably put on an entity or value object. These could be a complex calculation that needs input from multiple domain objects for example.

Most software systems need to persist data somehow. In DDD repositories are used to access persistent storage. They provide access to data using the metaphor of a library.

Services

Not every element or concept in a domain has attributes. Probably it only describes a logic or rule that gets data from other objects. For such cases, DDD proposes to model a (domain) service.

Domain services are stateless objects with methods (commands or queries) that take domain objects as arguments. They don’t need to be created (instantiated) by a factory because of their statelessness. Therefore we can use them by just passing the correct parameters to their methods.

For example, let us consider the addition of an item to the basket of a webshop. The business requires that baskets contain only products which are available in our inventory. Before adding a product, we need to check the inventory. This logic doesn’t fit well on the basket entity’s add method because we don’t want it to depend on the inventory. Also, other baskets could already contain the item too. However, it still is a business rule that we would like to express in the domain. Therefore we create a domain service which counts how many items of the product are in the baskets and checks if the inventory has more than this amount available.

The AvailabilityAssessor nicely encapsulates the business rule, and we can remove responsibility and a dependency from the basket.

Repository

Repositories in DDD are used to access data from persistent stores. In contrast to many persistence libraries which use the language of databases like save and load, repositories use a library or set metaphor. Save is called add, load methods are getter or finder and delete becomes “remove”.

Below is a simple java interface of a repository following these conventions.

The add-method is used for new objects only. When we remove an object from the repository, we should delete it from the underlying persistence store.

Modifications are not the concern of repositories. From a domain perspective, we assume that all changes are persisted automatically. The pattern states that we should handle transactions in the application layer, not the domain.

We don’t need a repository for every entity or value object. Instead, repositories handle groups of domain objects together. These groups are called aggregates which is another tactical design pattern in DDD which I will introduce in the next post of this series.

Reconstitution

Eric Evans writes in his original DDD book [Eva04] that populating the domain object with data from the persistence should not be implemented in the repository but the factory. First I was skeptical about this statement. Why introduce another indirection and complicate the system?

There are many different ways to store data to persistence like tables in relational DB, documents in a NoSQL-DB or events in event sourcing system. I think in those cases where we have some generic representation of the data in persistence like events or key-value pairs it feels natural to pass them to the factory for reconstitution.

However, if we load the data into specific objects already from the persistence how do we pass them to the factory? The factory shouldn’t depend on the persistence implementation. Therefore we cannot pass the data objects to it. We could use simple data types, add another interface or copy the data to a generic structure probably. I think it depends if this effort is worth the gained separation of the reconstitution concern.

Wrap Up / Final Thoughts

When some domain element or concept doesn’t fit on a domain object, the domain service pattern can be used. By keeping those services stateless their usage is simple. It could be tempting to build many services that hold big parts of the logic. This practice is not recommended though because data is split from the logic which complicates clients.

I found the Repository pattern very compelling because it separates persistence concerns from the domain. While writing business logic, I don’t want to think constantly of when to commit or what to do on a rollback. Things like these should be handled when writing higher-level workflow logic.

[Eva04] Eric Evans: Domain-Driven Design – Tackling Complexity in the Heart of Software (homepage)

View More

This post is about the value object pattern and the factory pattern which are tactical patterns in domain driven design (DDD). Value objects define the second kind of domain objects besides entities. Their main characteristic is immutability: Attributes of a value object never change.

Factories are responsible for creating new objects and validate them. They help us identify and separate this functionality from the other parts of a domain object.

Value Objects

Value objects do have attributes and methods as entities. Attributes of value objects are immutable though which implies that methods of value objects can only be queries, never commands that change the internal state of an object. We can pass value objects to clients through getters for example without worrying that they change them.

Many objects can be modeled as value objects instead of entities because they are defined through their attributes. These objects measure, quantify or describe things in the domain model. Because they are so easy to handle we should model as many value objects as possible.

No identity, no lifecycle

Value objects don’t have an identity that is used to compare them. We compare them by their attributes. When all attributes of a value object match another one they are considered equal. Therefore we can construct a value object from its attributes when needed and destroy it afterward.

Without the burden of maintaining an identity (create a unique id, associate it with other entities) value objects are a lot easier to handle than entities.

Example

An example of a value object is the material of a tabletop. The tabletop’s main material can be wood, stone or steel for example. Instead of adding attributes for kind (wood, steel), name (oak, chromium steel) and thickness directly to the table object let us create a value object called material.

Now the material is explicitly defined and named. We can interact with the table without thinking about the details of the material.

Maybe you decide the replace the tabletop with another after some years. However, because value objects are immutable, the material object cannot be changed. We replace it with the new one. Just like in the physical world, stone can’t be transformed into wood magically.

In code, the replacement boils down to setting new attributes and save them to persistence. If we modeled the material as an entity with identity, we first would need to delete the old material, generate a new id and associate it with the table object.

Now on to the second pattern of this post, the factory.

Factory

The factory pattern in DDD can be seen as a super pattern for the Gang of Four (GoF) creational patterns. Factories are concerned with creating new entities and value objects. They also validate the invariants for the newly created objects. We can place a factory on the entity or value object itself or an independent object.

Factories that are placed on the same object they create are either factory methods or prototype methods. The factory method creates a completely new object from the method parameters. The prototype method uses an existing instance to derive a new object.

When the creation logic is complex or has dependencies that are not needed by the created object it is best to create a separate factory. This factory could then provide multiple ways to create new instances.

Wrap Up / Final Thoughts

Value objects simplify our lives by releasing us from thinking about mutated state just like in the functional programming style. By combining them with entities, we can get a simple but powerful model within our code.

Factories draw a clear line between creation logic and other concerns in the code. When we name them explicitly and consistently, readability of our code should be improved.

[Eva04] Eric Evans: Domain-Driven Design – Tackling Complexity in the Heart of Software (homepage)

View More

The first pattern of domain driven design (DDD) I would like to take a closer look at is the “Entity” tactical design pattern. We all know the term “entity” and may have a certain picture in our mind when we read it. I was first introduced to it while learning about entity relationship diagrams that are used to design databases. However, in DDD an entity is an element of the domain model, a kind of domain object.

The domain model entity element has distinct characteristics which separate it from value objects, another pattern that DDD uses to model domain objects. The main differences are that entities have an identity which stays the same during their lifecycle and that they are mutable whereas value objects are immutable.

The Pattern

An entity is a domain model element that represents some domain object. It has attributes and methods. For example, a ship that has a certain name and capacity.

One of the main characteristics of an entity is that it has an identity. The identity never changes through the life cycle of an entity. An example of this is a person who has a certain name. When the name changes if that person is married for example, the identity has to be preserved.

When comparing entities with each other, we cannot rely on their attributes. Two person objects with the same name value don’t necessarily have to represent the same Person. On the other hand, consider a contact detail object with an attribute phone number. This object doesn’t have an identity on its own, every contact detail object with the same phone number could replace it with no change in meaning.

Entities have a life cycle which starts when they are created. They can be loaded from a persistence store, changed due to an event or action and then stored to persistence again. At the end of their lifecycle, they are destroyed. For example, a car is built which starts its lifecycle. Then after some years in use, some parts are replaced. Finally, when we take the car to the scrap yard where they dismantle it, its lifecycle ends.

Commands and Queries

Methods of entities are either commands or queries. Commands are used to change the state of the entity, for example set an attribute to a new value. They never return state. In contrast, query methods should never change the state of an entity but return some value.

This distinction makes it easier to reason about our code. We know that a query method doesn’t change anything. When calling a command, we know that we may better carefully inspect what it does exactly.

Validation of invariants

The entity pattern advises us to model the invariants of an entity. Invariants are facts or rules that are always true after a command made a change to an entity. For example, a car needs to have always exactly four wheels. So after the command that changes the wheel of a car, we need to check this invariant.

Therefore after each command or series of commands that we execute on the entity we need to validate it. Even when factories create new entities, they should be in a valid state from the beginning of their life cycle.

Associations

Eric Evans also discusses associations in his DDD book [Eva04]. Many associations are bi-directional in nature, and therefore we model them as such initially. If we translate those directly into the software, the model becomes very entangled and hard to maintain. Therefore we should strive to minimize associations within the model and code.

Three ways to reduce associations are imposing a traversal direction, reducing multiplicity by introducing a qualifier and removing the association altogether. The following sections describe a sample of each possibility.

Impose direction

Imagine my favorite sample of the webshop. There are baskets to which users add products. The association between baskets and products is many-to-many. Does this imply that we need to maintain a list of baskets inside the product entity?

Most of the time it should suffice to be able to query the basket for its products. A product doesn’t have to know in which baskets it is stored. That’s a question the application may never need to answer. If it does, we can query the repository (database) for the answer.

If we needed to maintain both directions within the model, every addition of a product to the basket would need another operation that adds the basket to the list of baskets of the product. By imposing the direction, we can simplify the code.

Reducing Multiplicity

The following diagram shows the association between student and subject. It is a many-to-many association because students study multiple subjects and subjects are studied by multiple students.

To reduce the multiplicity we could, for example, add time slots to the model. At a given timeslot a student can only study one subject. Therefore the multiplicity is reduced to one-to-many.
This association is much easier to maintain in the code of the model.

Removing associations

The ultimate simplification is removing associations altogether. When the association is purely informative for example, or when it is used only in a given context we may better remove it. For example, the application for a publishing company may records reviewers of a book during the publishing process. However, once the book is printed and added to the store of the company, there is no need for the association to the reviewers anymore.

Wrap Up / Final Thoughts

The entity pattern defines domain entities which can be modeled and translated to code. It divides methods into commands and queries with clearly defined semantics. Entities maintain a lifecycle, and we can minimize their associations in multiple ways.

The next pattern in the series will be value objects. Generally, they should be preferred over entities when modeling. Let’s see why in the next post.

[Eva04] Eric Evans: Domain-Driven Design – Tackling Complexity in the Heart of Software (homepage)