DDD revisited

Introduction

Way too many times I encounter applications that claim to have a domain (model) and that domain driven design has been used to develop it, but in reality what I find is a collection of entities or shall I say DTOs each one having a bunch of properties but no real logic associated. Furthermore I can find a lot of services of all kind that contain a colorful mixture of business logic and/or infrastructure logic. If the application is also using some form of message bus like NServiceBus, Mass Transit or Azure Bus, to just name a few, then we certainly also will spot some messages that are sent around from one module to another or many others. Unfortunately the messages often have very generic names that contain the words “update”, “modify”, “insert” or “delete” and the payload of the messages is really fat, dozens of properties that are sent on their way. Frequently it is not immediately clear from their respective names whether the message is a command or an event. We have to dig deep into the implementation to find those things out.

I truly wish what I just wrote above was exaggerated or would only apply for “old” applications that have grown out of control. But the sad truth is that this applies to many projects that have started on the green field and are only a few months old. Why is this the case? There are certainly many reasons – lack of knowledge is one of the more important one.

DDD – What’s relevant?

When we want to create a new application, ideally from grounds up, and we want to use DDD then we should consider this: not everything that has been written in the blue book is equally important. Unfortunately the first 14 chapters or so deal with implementation details that have more to do with good object oriented programming and not so much with domain driven design. The last few chapters of the book contain the really interesting stuff. But a lot of developers don’t read so far and have already started to implement their applications.

Finding the common language

When we start a new project then we need to first try to truly understand the business domain for which we build the application. We need to talk to the stake holders and domain experts (yes, normally that are representative of the client for which we build the software) and try to understand their language. We need to listen carefully what they say and how they say it. Are they using certain words that everyone working in the domain automatically understands and uses in the same way? Are these words unambiguous and intention revealing? If not then we need to ask questions and require the domain experts to describe their terminology in more detail or with other words or even use analogies. One of my favorite “games” is to ask the domain experts how they would do their tasks of which we are talking in absence of computers. What would be the actions and what the object, things, concepts or nouns?

Over time (yes this can take days or weeks to do it right) we will have a common vocabulary on which we all agree – the stakeholders, domain experts, business analysts, architects, developers, testers and QA engineers. We will call this vocabulary or “language” that we now have in common the ubiquitous language.

Note that the ubiquitous language is probably going to evolve over the duration of the software project as we get a deeper and deeper understanding of the problem domain including all its many subtleties and edge cases.

Breaking down a complex problem

Once we have found or defined the ubiquitous language of the problem domain we can start to model the domain. But most often the business domain for which we are going to write the software is rather complex and hard to overlook and/or understand all at once. Thus we need to start breaking down the whole complex domain into smaller pieces of lesser complexity. It is the same approach that we use when we eat. We are not able to swallow a whole steak at once but need to cut it into pieces and then eat one piece after the other. We can do exactly that with every problem domain. With the help of the domain experts we need to identify the sub-domains or areas that we can isolate from each other and look at them individually and solve them in isolation. When we do that then we call those sub-domains bound contexts. A bound context is a part of the overall domain that can be solved individually and that has clear boundaries and interacts over well defined interfaces with other bound contexts.

Defining interfaces and contracts

Now that we have broken down the complex business domain into smaller and less complex bound contexts we need to think about how these bound contexts interact with each other. Each bound context should look like a black box from the outside. Implementation details don’t matter if I am not part of the bound complex. The interaction with a bound context happens over well defined interfaces using carefully crafted contracts. Once again this wonderfully matches with our real world experience. If we want to do business with say an insurance then both parties, I and the insurance company have to agree on certain contracts. Contracts describe in detail how we do business together. There are no dis ambiguities. And once established and mutually signed it is not easy to change a contract – it is totally possible but it is not free. The same way we should think when we define the interfaces and contracts for our bound contexts. Contracts are the messages that we exchange between the bound contexts – commands and events. Here the name and payload of the contracts matter. The name gives the context of the command or event and the payload contains the delta that is needed to go from one state to the next.

We should clearly distinguish between commands and events. A command always has a target. It is exactly one target. The target of the command can either accept or reject a command. The result of a command usually is a change in the system. Something has been done that changed the state of the model. On the other hand an event can have zero to many listeners. Yes that’s right, events can be ignored… but events can never be rejected since they tell us what has already happened. To clearly distinguish commands from events we should use names written in imperative for commands and names written in past tense for events. The names should reflect the ubiquitous language that we have established.

DDD – what we should avoid

If we want to use domain driven design while developing a solution for the problem domain we’re working in then we should avoid a few pitfalls.

A data-centric world

In the past most line of business applications were data-centric applications. The data model was the first thing that architects and engineers would design. Everything else would follow. People would say “… at the end of the day data is what’s counting. The data that we collect is our asset. Applications that collect and/or use the data come and go but data remains…”. And although data remains… it is just plain wrong to claim that data is all what counts! Data on its own is meaningless. Data alone is dead. Only logic gives the data a meaning. And the very same data has different meaning in different contexts. Thus we should always start with the context and the logic.

A data-centric view of the world also lead to the fact that databases are often used as integration point. Many different applications access the same database. This leads to a lot of problems in the long run. To give you a good analogy of what I am talking about let’s imagine that I have a wallet with some money in my pocket. Now my friend ran out of cash and wants to borrow 10 bucks. How does our world work in this case? a) my friend politely asks we for 10 bucks and I open my wallet and hand him out the money or b) my friend takes my wallet out of my pocket (without me realizing it) and takes a 10$ bill out. Thus: in a LOB application never use a database as integration point.

When I am implementing an application the ERD is one of the least important things to me. I do not let myself and my domain model be driven by the choice of a data store or data model. For me LOB application does not automatically mean that I have to use an RDBMS and that my data model needs to be in 3rd normal form!

Talking about implementation details

DDD is NOT primarily about entities, value objects, services, repository or factory pattern and the like. These are all implementation details. They have no real meaning until we have done our homework and defined the ubiquitous language, the bound contexts and the interfaces and contracts. If we start too early with the implementation then the result is an anemic domain consisting of a collection of DTOs surrounded by an awful lot of services and business logic that is spread over all places.

Using techno babble

In our application we should never use concepts or words like save, update, insert, delete, handle, manage, etc. These are either very technical terms or abstract concepts with no specific meaning. If I have a saying then one of the first things I do is ban the “Save” button from the UI of the application. Save is not a business concept. Imagine a world without computers doing business – do the involved people ever use a sentence like this “… on, let me save this…” (one exception is saving money on a bank account). Also in a real business we never “Delete” or “Insert” or “Update” something. Do we delete an employee when he is no longer required in the company?

Very generic terms like “manager” need to also be avoided. What does a manager do? What does “manage” mean? No, no, we need more context please!

Database transactions

Although DB transactions are a good thing on its own, it is wrong to overuse them. Much more important than DB transactions are business transactions. Whilst by definition DB transactions are fully consistent (and short running) business transactions are not. A sample of a business transaction that you probably are very familiar with is what’s happening at Starbucks when in the morning you order your favorite coffee. This is a “long” running process with many possible “inconsistent” intermediate states and asynchronous tasks. Yet this is what works, is scalable, and wildly accepted by everyone.

Thus when modeling your domain using DDD don’t think about DB transactions (or even worse “distributed transactions”) at all. Think about possible actions, their outcome and about compensating actions if something fails. And you will see that you will solve mainly business relevant problems and that you do not fight with technical problems.

Conclusion

Using domain driven design successfully means that we need to do a few things very well from the beginning, mainly define a common vocabulary called the ubiquitous language, break down the overall complex problem domain in to smaller sub domains called bound context and to carefully define the boundaries and contracts used between the individual bound contexts. On the other hand we need to avoid certain practices that are all too common among software developers. These are using a data centric view when modeling the problem domain, focusing on implementation details like entities, value objects, services, etc. instead on the core concepts discussed above, using generic and developer specific terms and concepts when implementing the application and finally overrating DB transactions instead of focusing on the business processes or transactions.

About Gabriel Schenker

Gabriel N. Schenker started his career as a physicist. Following his passion and interest in stars and the universe he chose to write his Ph.D. thesis in astrophysics. Soon after this he dedicated all his time to his second passion, writing and architecting software. Gabriel has since been working for over 25 years as a consultant, software architect, trainer, and mentor mainly on the .NET platform. He is currently working as senior software architect at Alien Vault in Austin, Texas. Gabriel is passionate about software development and tries to make the life of developers easier by providing guidelines and frameworks to reduce friction in the software development process. Gabriel is married and father of four children and during his spare time likes hiking in the mountains, cooking and reading.
This entry was posted in DDD, design, How To, practices. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #1842()

  • Alper

    Very informative. This should be required reading for every developer who decides to use DDD.

  • Matthew Lengenfelder

    spelling error – “Fining the common language” should probably be “Finding” or “Defining”.

  • Dan Keller

    Do you work at my company? the data modellers have actually told me the same line, applications come and go, but data is forever line. Almost word for word. Freaky

  • gilligan_MH

    I would say that Vaughn Vernon’s Implementing Domain Driven Design book is the new “Blue Book” for us. It tackles everything in the right order IMO.

  • Eric Fung

    Just my afterthoughts …

    I recall, in early days (1980s’) the argument of Process oriented Design vs Data oriented Design. Along the same thoughts “Applications that collect and/or use the data come and go but data remains…” so Data oriented Design seems then prevail. During the same time large corporation would build most IT application system in-house, having a dream goal to have one single DB with unified, organized, consistent, and, throughout-thought schema for all different inhouse IT development team. (vs undersired isolated data silo)

    Then in 1990′s most large coperation turns to vendors instead of developing their own LOB application (e.g. ERP) while there may be more than one such applications, and compound with various inhouse developed system / legacy system, etc. So no single DB can hold everything together, then we have Enterprise Application Integration (EAI) to tackle the co-operation among different systems.
    and in 2000′s focus shift to Data Warehouse, to bridge the discrepency of terminology / measurement / timing of data collection among all such different systems in an enterprise, aiming to provide a single version of truth for management.

    So just see the arguments from Gabriel for object orient design vs domain driven design (I should owe him an appology if I misinterpret his idea here) , it leads to my own revsion …

    I am not saying the world just kepts repeating, rather I see each stage those who advocate a new design paradigm is trying to address short coming as they witness / experience arising from the old thoughts.

    Though I will see that much debate would become an ideology issue, while a more day-to-day issue would be such short coming, if relevant to the situation, that we must address, no matter through adopting new design paradigm / evolution from the old.
    So I would be grateful having Gabriel and others to share more such insight / experience on the shortcoming with the original mis-led design approach, as well as how such pain point is overcome through the new approach.

    • gabrielschenker

      Well, one shortcoming is certainly using the DB as an integration point as I mentioned in my post. If many parties can change the (same) data one has to be open for a lot of surprises. The quality of the data will be inconsistent or bad. Different parties have different rules/business logic on how they deal with the data…

      • Eric Fung

        Thanks a lot for Gabriel’s advice !

        I also experience the pain how DB centric cross application integration would cause before (e.g. As consumer of another subsystem’s data, your application may break if another parties only twist a little bit on any table columns’ usage, and vice versa, you may be so reluctant to even minor change on any part of existing DB schema, as the impact analysis go well beyond single teams’ scope you manage, and I also think thats why encapsulationin of object-oriented approach being praised, not matter such subsystems runs on one single DB or not)

        However, would you mind share how as described “DTO with no real logic”, or, only having just message with “update”, “modify”, “insert” or “delete”, harming the system as a consequence (I just guess may be it can cause subsequent maintenance issue ? performance issue ?, but not able to figure it how), as well as how DDD overcome such problem ?
        (Sorry if such question may be just simple as ABC to any DDD practitioners, though I would be grateful as their answer could open me up to a new era, from an outsider to this new paradigm)

        • gabrielschenker

          I’ll discuss some or all of these topics in an upcoming post. Stay tuned.

  • Pingback: From my reading list #26 – May 25th, 2015 | Pascal Laurin()

  • Paul

    Thank you for nice overview, Gabriel.
    Trying to grasp DDD ideas I was wondering how can they influence HTTP API exposed by the backend.
    You’re emphasizing once again that raw data-manipulation verbs like “Insert”, “Update” or “Delete” must not be used.
    Does it mean that DDD conflicts with RESTful approach which encourages standard verbs like PUT, POST and DELETE together with URLs based on nouns, not verbs?
    Can we say that RESTful APIs are inherently data-centric and SOAP offers better support of DDD?