Why you need domain-driven design (even though you think you don't)

Have you ever developed or worked with a software system that was "just right," even if it didn't stay that way for long? Once the skeleton of the system was solid, things got easier, and implementing new features seemed as natural as snapping together Lego bricks. What was it that made that experience so magical?

It wasn't magic. Whether you realized it or not, the model in the code was harmonious with the underlying domain. If that's something you want to happen every time, domain-driven design (DDD) is for you.

I've been an object-oriented software developer since the mid-'80s, and in that time I have seen many methods come and go. While I seldom achieve or sustain that elusive state of coding bliss, it has occurred several times, in different paradigms. The first was in structured programming (with big design up front). More recently, and more often, using DDD. Although anecdotes aren't evidence, I consider DDD to be the current best practice. Unfortunately, it isn't very popular, and those who use it typically don't do it terribly well.

That's a shame.

Testing in the Agile Era: Top Tools and Processes

The unifying principle

Every software system ever built has a model at its heart. If this model matches the underlying domain well, the software will accept enhancements more easily, and it has a much better chance of surviving and thriving intact for years. The model may not be obvious; it may exist only in the mind of the developers, but it exists nonetheless. Elegant designs are possible in any paradigm. If the model reflected in your code is aligned with the domain, the code flows.

It's this alignment that matters, and achieving and maintaining alignment is the fundamental purpose of DDD.

There's always a model

Your code has a model within it. If the code isn't a model of the business domain, then what is it? If you're not intentionally modeling the domain, then what are you accidentally modeling instead? Even in the best systems, your code will reflect some aspects of the domain model well in some places, but not so well in others.

Consider this example: Your team is building an application that will support SaaS customers, and you're interested in the sign-up process. The story the team is playing says, "As a customer, I want to be able to sign up for a subscription so that I can use the service." You look at the code and find that the requisite method is in the "customer" class, which makes sense, but that it's named CreateCustomer.

Ouch.

Developers tend to think and talk in development terms, which naturally results in inadvertent models of how instead of what and why. This is common, and it's a tar pit, because developers tend to follow established patterns. What's more, once the true purpose of the code is obscured, it's unlikely that anyone will unearth it.

Yes, the functionality of the method named CreateCustomer does everything required to complete a customer signup, but the language it uses describes its own implementation, not the domain activity. Naming the method SignUpForSaaSSubscription would better reflect the actual domain activity and make the intention of the method clear.

At a trivial level, it's all about the names you use for things. At the level above that, it's about the way that you combine and activate things to produce business value. At the level above that, it's the causal and relationship (semantic) model that keeps everything cohesive, coherent, and aligned with the business. This alignment can't come from an implementation-focused model. You must use a domain model.

A business-applicable model doesn't have to be couched in DDD terms to be good. If your business model is naturally and fully described by a database operations create, read, update, and delete (CRUD) model, then that's good enough. It's the alignment that matters, and continuous alignment is the goal.

The model provides the framework

Once you've captured a useful piece of the business in the model, you have a framework on which to support multiple applications. It's not a framework in the literal, technical sense, but a framework in the sense that it can guide the thinking and construction of solutions sufficiently well. But this isn't a one-shot activity.

It's a journey, not a destination

Striving for model-domain harmony never ends, as long as the business keeps changing. But that's alright, because DDD is a continuous process. It keeps the guardrails up, the feedback flowing, and the software on track with the business. DDD does this strategically, tactically, and philosophically.

DDD philosophy

DDD talks a lot about the ubiquitous language of a domain (also called the domain language). Ubiquity is a goal, a guide, and the central organizing theme. Everyone, technical and nontechnical, must speak the same language, use the same terms, and give the same names to the same concepts. If not, group understanding will be inaccurate, the resulting communications will be imprecise, learning will be fractured, and the software will decay over time. The definitive source of names, definitions, and descriptions is the subject matter expert (aka domain expert), not the software developers.

This quasi-Zen emphasis on pure definitions and unified communications, within specific boundaries, is the glue that holds it all together, the philosophical principle that forms the guardrails that keep everything else on track. The strategic, tactical, and technical aspects of DDD are intended to support and enforce this philosophy. You model the business in business terms (and model the domain in domain terms) and then protect that model from corruption in conversation, design, and implementation.

Strategic DDD

The strategic aspect of DDD aligns software development teams' efforts with the interests of the business. It helps when deciding what to focus on, usually by identifying one core domain. This may be a specific area of business or even a specific slice that's critical. The strategic focus keeps your major efforts devoted to what's most important to the business now. This prevents the sluggishness and paralysis of the everything-we-do-is-most-important blanket that often smothers software development efforts, while effectively accumulating corporate knowledge in the software.

Tactical, technical DDD

The tactical, technical aspect of DDD guides the implementation process with the fundamental purpose of protecting the model from corruption. The patterns and architectural structures commonly associated with DDD (though not necessarily first invented or discovered by DDD) flow naturally from this constraint, to provide the requisite layers of protection.

The patterns aren't the point

Sadly, many developers, when first learning about DDD, scoop up the technical patterns and don't tarry long enough to absorb the philosophy or strategy. Using the patterns of DDD without adherence to the philosophy of DDD reduces the method to a cookie-cutter, mechanical approach to design that can create costly and unnecessary complexity. If you get the context boundaries wrong, it will be difficult to apply and maintain the code in spite of the otherwise desirable patterns. If the model in the code is lax about its use of domain language, it will rapidly lose alignment with the business.

Why it's hard

In many ways this is why DDD is considered hard to do right: it takes a certain amount of self-discipline to adhere to the philosophy and requires another level of restraint to resist designing when you should be modeling. It also takes courage to keep asking "What does this really mean?" and "Why does this happen?"until the deeper model is uncovered. Finally, it requires patience to keep refining, refactoring, iterating, and accepting feedback until the model, the code, and the business coalesce into a cooperative synergy.

Do it anyway

If you're building simple applications in a simple domain, your model will also be simple, and so shouldn't be excessively time-consuming to discover. That doesn't mean that crafting it will be easy, though. Above all, you must commit to learning about the business. Many developers only have eyes for gadgets, technology, and tools, while business-related things are regarded as irrelevant inconveniences. But you can't help the business develop its capabilities without understanding the business. There's no magic tool to Google the minds of the subject matter experts, and no mobile app will let you skip having those detailed conversations about how the business works.

A little DDD can go a long way. Even if you decide not to continue DDD practices past the initial model, or only go for a few iterations, you'll be able to make that decision from a position of knowledge, instead of guesses and wishes.

Testing in the Agile Era: Top Tools and Processes
Topics: Dev & Test