Domain-Driven Design Immersion Class

I just wrapped up a four day Domain-Driven Design Immersion class with Eric Evans (author of Domain-Driven Design) and Paul Rayner. The class was put on by Eric’s company, Domain Language. If you’re looking for training or consulting in Domain-Driven Design, I highly recommend that you get in touch with them. I’d like to share some highlights of the class here.

Putting the Model To Work

Domain-Driven Design is a set of three guiding principles:

Focus on the Core Domain as that is where the complexity is. Technology plays a supporting role, use it as needed.

Explore the Model in a collaborative process involving both Domain Experts and software practitioners.

I should point out that the word “Model” has many different meanings in software development. Within Domain-Driven Design a Model is a “system of abstractions that describes selected aspects of a domain and can be used to solve problems related to that domain.” Those familiar with the Model–View–Controller (MVC) pattern should note that the word “Model” within the MVC pattern has a different meaning than “Model” within Domain-Driven Design. Within Domain-Driven Design a Model is a conceptual tool used to understand a Domain. An example that was used in the class was the game of baseball. A Model of the baseball Domain would include concepts such as strikes, balls, and outs. The classes and objects representing these concepts would not be the Model.

You might be wondering what the difference is between the Domain and the Model. The goal with Domain-Driven Design is not to create a Model of reality. Even if you could come up with some objective view of reality this would not be very useful. Instead, we are trying to understand (and perhaps develop) the Models that Domain Experts already use to understand the Domain. It’s important to note that Models are only useful for a particular purpose. What are you trying to do with this Model? Trying to use a Model designed for a different purpose will lead to a less than optimal outcome.

The Model Exploration Whirlpool might be a useful reference if you’re looking for concrete guidance on how to explore Models, especially in an Agile or Lean setting.

Building Blocks

Group Entities and Value Objects into Aggregates. Entities are objects defined by a thread of continuity and identity. Their only responsibilities should be around identity and life cycle. Within a customer relationship management (CRM) system a person would likely be an Entity. Note that context matters: a person in another context may be a Value Object. A Value Object “is an object that describes some characteristic or attribute but carries no concept of identity.” Using the CRM example again, a phone number might be a Value Object. Again, context matters: if you’re a telephone company then a phone number may very well be an Entity. Treat Value Objects as immutable. Delegate business logic to Value Objects, identity and life cycle are plenty of responsibility for Entities. Grouping these Entities and Value Objects into Aggregates is useful when defining transaction, distribution, and concurrency boundaries.

An interesting topic covered in the class that I don’t believe was in the book was the idea of Domain Events. A Domain Event is something important that happens within the Domain that may lead to a state change in a domain object. Instead of keeping track of the current state of an Entity, you can instead compute this state from the currently known Domain Events. Using a baseball analogy again, a Domain Event might be a strike. Domain Events can trigger other Domain Events: three strikes triggers an out. The current state of the game can be computed from all of the Domain Events.

Supple Design

Since this has been a topic of conversation here on my blog and on Twitter, I plan on writing another blog post on why Value Objects need to be immutable. However, I want to point out here that if you think you need to change the state of a Value Object then instead have a method on that Value Object that returns another instance of the same type with the new state. If your method takes any arguments then have these arguments be of the same type as the Value Object. This concept is called “closure of operations” and is covered in Chapter 10 of the book, Supple Design.

While I won’t go into the details here, there are several other useful patterns in creating supple designs including intention-revealing interfaces, side-effect-free functions, and assertions. Note that “supple” is not the same as “flexible”. A flexible design can be easily modified, but a supple design is a design that fits comfortably with the Domain.

Strategic Design

Strategic Design involves managing the interactions between Bounded Contexts. In my understanding, strategic design is most applicable in large teams or groups of teams. It starts by drawing a Context Map of the actual current Bounded Contexts, not what you want the Bounded Contexts to be. Some patterns to describe these relationships include Partnership, Shared Kernel, Big Ball of Mud, Customer/Supplier, Conformist, Anticorruption Layer, Separate Ways, Open Host Service, and Published Language. The details of these patterns can be found in the book.

Distillation

There are always multiple Models. Some of these Models my represent your Core Domain. Others may represent a Supporting Domain or a Generic Subdomain. Work with business leaders to create a Domain Vision Statement so that you can identify which is which. One good question to ask a Domain Expert at the outset of a project to get at the Core Domain is, “What keeps you awake at night?” Other questions to ask include:

“What makes your system worth writing?”

“Why not buy it off the shelf?”

“Why not outsource it?”

Once you’ve identified your Core Domain this is where you should focus your modeling efforts. Put your best available internal developers and modelers on the Core Domain and make sure that the Core Domain is isolated in a clean, Bounded Context.

Summary

Don’t settle on not having access to a Domain Expert. Domain-Driven Design is a creative collaboration between Domain Experts and software developers. Cultivate strong relationships with Domain Experts, focus on the Ubiquitous Language, listen for clues in conversations, and be open to shifts in assumptions that destroy your understanding of the Model—this is where breakthroughs come from!

6 Comments

CQRS is mainly focus on distributed systems but the concepts work well without a distributed system. I have been doing a fair bit of research on it and think it works well in PHP’s share-nothing architecture. One of the main reasons I like it is that I have found when trying to apply DDD with something like DC2 or my own mapper implementation you end up with a fairly heavy weight interaction with the Domain when querying (for display), this then forces you to workaround your ORM or mapper to pull large sets of data, as CQRS separates read/write it makes it much easier to query data for display. Also the concepts about capturing intent seem to make good DDD sense to me, plus theres a whole host of other cool ideas, all of which you can mix and match to your requirements.

My current web development tools of choice are Zend Framework (ZF) and Doctrine2 (D2). ZF doesn’t really promote/specify/designate/etc a specific pattern/implementation for the M in MCV; I think that is a (very) positive thing in some respects but the flexibility leaves you with so many options it is somewhat of a daunting task to figure out how to approach the topic/problem.

That said, I think the Model is the cornerstone of where DDD comes into play. I’ve been looking into several different ways to incorporate the concepts of DDD with ZF and D2, but I haven’t been able to find a cohesive way to create my domain model where it isn’t tied back to the ZF application (maybe that is an unrealistic goal).

My question is how are other people (in the php world) applying DDD concepts. What tools/methods are they using and are there any chance of being able to see source code (or at least examples)?

@Jonathon Applying DDD is fairly simple in ZF, the trick is to not use ZF 🙂 What I mean by this is that you need to make your Domain outside of ZF and then use ZF to call your Domain, if you are finding your Domain tied to ZF it sounds like you have Fat Controllers. In this case you need to create a service layer and push the controller stuff into those services. A good test that I use is “Can I call this from a unit test?”, if yes you are going in the right direction.

Also one thing to watch out for is a Domain that does CRUD operations, if your Domain is CRUD you are not modelling behaviour and are likely falling into the Anemic Domain Model Anti-pattern.

I must say that I’m not at all versed on DDD, but I can’t agree more with using a Bounded Context. That’s key to manage complexity and to get less headaches from anything beyond very small projects.

I suggest not to leave Bounded Context just for “large teams or groups of teams. “. We are used to dealing with business processes that by nature have a high level of complexity, making sure you reduce the scope of the what you need to think about at the same time does wonder to keeping everything manageable.