I recently had the chance to finish reading Eric Evans’ book ‘Domain-Driven Design’ and I figured I’d take some time to highlight some of the key concepts and takeaways from the material, both for the benefit of my future self and to also share my thoughts with the rest of the world.
The overall flow that ties the book together is the following:
Great Communication -> Great Model -> Great Code/Design -> Great Experience
Let’s talk about each in turn:
This is probably the section of the book that resonates with me the most. It is also one of the more underrated aspects of the software development lifecycle, even though it permeates all of its phases. The ability to effectively communicate with members of your own team as well as members of other teams is crucial. Possibly even more important is being able to recognize when effective communication isn’t taking place.
It’s paramount to pin down the meaning and usage of terms within the team and within the organization. How many times have you heard coworkers discuss what an integration test is vs a functional test? What about a system test? How many times have you had to discuss what a feature is vs a story? Or a task vs an improvement? How about the amount of effort involved for ONE story point? These definitions are technical in nature but the point remains clear: it’s imperative to provide precise meanings of terms within a context.
Outside of a context or team a term can mean anything you want it to mean but within, it’s given a definition and the definition remains static. It may seem pedantic at first but failure to agree on a shared vocabulary will constantly hinder your team from providing value as clearly and quickly as possible. Note that the necessary quality of your communication with a party is inversely proportional to the frequency in which you communicate with that party.
A shared vocabulary between stakeholders and developers is a requirement for a rich model that can be leveraged throughout the project. Models aren’t only for developers. A useful model can serve as documentation for both developers and business/application users alike. Persons unfamiliar with the domain should be able to view the model and grasp the core aspects of the business and even better, the software systems that support it.
Likewise, this information can be used to set the stage for new developers to get acclimated with the codebase without even needing to read a single line of code. This is because a rich model serves as the foundation of the technical designs that ultimately become software systems. It is important to note that this shared model is something that only comes about when all parties are communicating clearly. Equally important is the fact that the design must be appropriate for subject matter experts and developers.
When modeling is done well a rich shared model will come to life. This is an invaluable tool that will pay dividends over and over again. It becomes self-sustaining because a rich model will lend itself well to a better model in the future leading to iterative refinements that will long outlast any one particular application built to support it.
On to the code for after all, we are supposed to actually *build* something right? Again here we see that proper diligence and importance placed on the preceding actions yields great results. The preceding actions in this case are communication and modeling. To quote directly from Evans’s book:
Write code that not only does the right thing but says the right thing.
A proper model is the scaffolding around which an application can be built. Once properly constructed, the applications code’s classes, methods, packages and other mechanisms for abstraction can reflect the model that was earlier designed. The same way that a particular programming language can frame the way a developer will think about solving a problem, so can the model. This will result in clearer, more expressive code than what would occur naturally. It also prevents different developers working on the same project from deviating too much from one another.
By being partially relieved of the burden of ‘saying the right thing’, more focus can be spent on *doing* the right thing.
If the previous three subheadings were summed up then on the right hand side of the equals sign would be the words ‘Great Experience’. The experience that I’m talking about here is the general sense or feeling that you get when working on an existing project. I’d like to talk about a few things in particular that contribute to this general sense.
Ease of travel across contexts and layers of abstraction.
One of the most frustrating things about software development can be the continuous context switching that must occur in your brain as you navigate through different areas of the codebase. Things that mean the same thing but are named differently. Things that are named the same but are different things. This is compounded when you have to communicate with a subject matter expert over a design and you have to constantly translate between business jargon and class/methods names. A rich model that yields clear code will avoid many of these problems.
Ability to Refactor
Aside from lack of tests, one of the biggest obstacles to refactoring a codebase is always the question what should it be doing?
This question can be answered in part by those missing tests, but a useful model can help to point one in the correct direction. When you’re able to pose these questions in a manner that the subject matter experts can understand, you’re more likely to receive a useful answer even though the original stakeholders/developers are no longer present. This is because a well-designed model is more likely to outlast the actual software itself.
Easier to spot logical bugs
Look at the following code and tell me if you can spot the bug:
int percentage = total/number_of_items;
It’s as clear as day that the numerator and denominator should be reversed. The well-named variables makes this much easier to spot than if you replaced them with one-letter variable names. One doesn’t even have to be able to read code to know that the code above is incorrect.
Now take this concept and elevate it a few levels of abstraction. The same concepts apply. Each object in the model should have a clear and consistent role. Awkward and nonsensical statements like the one above will present themselves when these defined roles are violated.
Much can be said about focusing on other areas of the software development lifecycle. This includes testing, requirement gathering and monitoring. But few of those areas come as close to determining a successful outcome as much as a well-designed and coherent model.