Domain-Driven Design: How Top Teams Build Software That Actually Works

As software developers/ software architects, we often come across the question, “Why should I use your application?” Most of the enterprise-grade applications that we work on, whether greenfield or brownfield, have already been worked on or are already present.

So why should a client use your application πŸ€”? What problems does it solve that other similar applications don’t solve, and how?

Creating an application that answers the above questions often starts with recognising domain-specific problems requiring technical solutions.
Working on medium to large software systems, you realise that the real challenge is not solving complex algorithms.
It’s orchestrating a system of many moving parts. As the codebase grows and microservices multiply, designing solutions that integrate seamlessly, leverage existing components, and extend the system thoughtfully becomes increasingly difficult.

Domain-driven design is a philosophy that provides principles and patterns to address problems faced while developing complex domain models.

Umm… what is a domain?

Every software program relates to some activity or interest of its user. The subject area to which the user applies the program is the domain of the software.

And what are models??

A model is a simplified interpretation of reality that abstracts the aspects relevant to solving the problem at hand and ignores the extraneous details. It is the teams agreed upon way of structuring domain knowledge and distinguishing the elements of most interest.

And hence, a domain model is a rigorously organised and selective abstraction of domain knowledge.

But software teams understand software and may not always have an idea of the domain they are working on πŸ˜΅β€πŸ’«

Knowledge Crunching

For a software team to understand the domain, they need help from the people who are experts in the given domain, a.k.a Domain Experts.

But… domain experts are not always aware of how complex their mental processes are, as, in the course of their work, they navigate all these rules, reconcile contradictions, and fill in gaps with common sense. Software can’t do this. It is through knowledge crunching in close collaboration with software experts that the rules are clarified, fleshed out, reconciled or placed out of scope.

Knowledge crunching is the practice of continuously exploring, questioning, and refining one’s understanding of the domain till they arrive at a simple view that makes sense of the mass. Many models are tried, rejected or transformed. Success comes in an emerging set of abstract concepts that makes sense of all the details. These models are never perfect – they evolve.

Ubiquitous Language

Domain experts have a limited understanding of the technical jargon of software development, but they use the jargon of their field(probably in various flavours). Developers, on the other hand, may understand the system and discuss it in descriptive functional terms, devoid of the meaning carried by the expert’s language.

On a project without a common language, developers and domain experts have to translate for each other. Translations blunt communication and make knowledge crunching anaemic πŸ₯Ά.

The domain model can provide the backbone for that common language, while connecting the team communication to software implementation. That language can be ubiquitous in the team’s work.

Let’s take an example of a cab service like Uber. The domain expert might tell the following points:

  • Rider requests a ride
  • The system finds a nearby driver
  • The driver accepts or rejects
  • Ride gets confirmed
  • Fare is calculated

For this, a developer might write this entire logic inside a method like:

assignDriver(rideId) {...}

While the method may be technically correct and functionally complete, it fails to capture the domain’s true intent and language.

When looking at a software design, we should actively go back and forth between the viewpoints of a developer/architect and a domain expert.

If we read the points given to us by the domain expert again, we would easily be able to categorise them into:

And this shift in mindset even reflects in our code, as our lines of code map to something a domain expert will actually say, like:

Ride.request(...)

DriverMatchingService.matchDriver(ride)

Ride.offerTo(driver)

Driver.acceptRide(ride)

Ride.confirm(driver)

The vocabulary of Ubiquitous Language includes the names of classes and prominent operations.

Leave a comment