Domain-Driven Design: is my design any good?

There are many ways to design a system. Some are more fit for purpose than others. If your team spans different roles, your design should facilitate teamwork. In this article, we’ll learn about a technique to evaluate that particular aspect of your design.

What is a software developer anyway?

When I mention at a dinner party that I work for a software company, most of the guests assume that I am a programmer. And although this is true, I still find it interesting that they jump to that conclusion.

Many people seem to believe software development to only be about machines. Somehow, it conjures the image of a lonely figure typing arcane symbols into a machine.

Of course, nothing could be further from the truth. It takes a lot more than programming to develop software.

Let’s suppose you picked a random software company and took a look inside. Chances are that you would find skilled individuals from many professions. Some of them would be programmers indeed. But there would also be product managers, UI and UX designers, security experts, and many more.

The main purpose of a software company is the development of software. But even so, it takes the concerted efforts of all these professionals to be successful.

But why is this the case?

Software development is not just about getting a machine to do something. It is also about figuring out what the machine is supposed to do in the first place.

I’d even go as far as to claim that figuring out what the machine is supposed to do is the more difficult part. Not only do we have to figure out what our customers want, but we also need to consider market forces, regulations and feasibility.

Change is the only constant

What’s more, anyone who has worked in a software company will know that we are chasing a moving target.

Just before we get the machine to do what it ought to do, we already desire it to do something else. Maybe there’s yet another feature for us to add. Maybe there’s another regulation we have to comply with. Maybe we find ourselves trying to cope with demand we didn’t anticipate.

All this keeps us in a state of perpetual motion. If we are not careful, we will burn ourselves out. We have to preserve our energy, take time to rest and prepare for yet another round of changes. Software development is not like a sprint, it’s more like a marathon.

Having a solid understanding of the software is critical for a team’s success. If you don’t know where you are, then you don’t know where you’re going.

But the systems we work on are complex. So complex, in fact, that they no longer fit into a single person’s head. This leaves us with little choice. We’ve got to narrow our understanding down to a single part of the system. Sadly, we lose the big picture as we zoom into the details of one part.

It also doesn’t help that our teams are in constant flux. Some people leave, some people join. Teams disband, teams form. In an environment like this, building and retaining expertise is a challenge.

As a consequence, we often have to rebuild parts of our mental models. And for that we rely on our artifacts. Different kinds of artifacts provide different kinds of information. Depending on what we want to find out, we can check the source code, diagrams, requirement catalogues or something else.

The source of truth

Regrettably, more often than not these artifacts contradict each other. Every time this happens, we have a choice to make: which artifact do we consider to be the source of truth?

I’ve come across two approaches in my career.

The first approach is to assemble a detailed requirements catalogue and to treat it as the definite authority. Such a catalogue is open to everyone on the team and gives everyone a chance to contribute.

The second approach is to declare the code to be the source of truth. This will guarantee that our models are always precise enough to be executed by a machine.

Neither approach is perfect though.

Requirements catalogues are often too vague. While it is possible to create imprecise specifications, it is impossible to create imprecise software. A vague requirements catalogue can cause more harm than good.

Declaring the code to be the source of truth creates an imbalance of power in the team. The software developers are the only ones who can read and understand it. Without their help, the rest of the team won’t be able to make progress.

If we combine both approaches, however, we can amplify the good parts and reduce the bad parts. How? Well, declare the code to be the source of truth, but design the code to be accessible to everyone.

Make the code accessible to everyone? Am I saying that everyone should become a software developer?

No, that’s not quite what I mean.

The software developers would still be the only members of the team to work with the code. But they would primarily design the code around the team’s shared mental model. They would use the team’s common language as often as possible. And they would separate the domain-specific parts of the code from the purely technical ones.

Testing the design of your code

If the developers did their job well, then they should pass the following test without effort:

  1. Invite a product manager or designer to pick a term from the team’s common language.
  2. Give a developer a few seconds to find that same term in the code.
  3. Ask the developer to read the relevant code out aloud.
  4. Look at everyone’s expressions. How much confusion is there?

Code that is a direct representation of the team’s shared mental model should cause little confusion. But if the code is packed with technical jargon and irrelevant detail, you’ll see lots of puzzled faces.

Let this test become your standard for judging the quality of all domain-specific code. Use it frequently to see how far on your journey towards a shared mental model you have come. It’s likely that the experience will be awkward in the beginning. But over time this test can guide you towards a better design for your system.

In the next article we will use this test to compare two versions of the same piece of code. One will follow the principles of Domain-Driven Design, the other one won’t.