The bottomline is this: you’re going to write better code faster, and your customers are going to be happier for it. Sounds good?
I’ve been in the software industry for about 12 years now and there’s a huge difference between the kind of software I saw and wrote then vs now.
In the past, software had a greater focus on storing user input, making it available for analysis and reporting, essentially replacing paper-forms and large archives. A program acted as an interface to the database, and that was basically it. Those were data-centric applications.
Lately, though, systems have evolved to perform business tasks, automate work and fetch information on their own, sparing user input partially or completely. Past systems did it too, but it was seldom while now it is often the case.
The data-centric architecture
Scaffolding tools emerged to increase productivity when developing data-centric systems. The workflow is very straightforward: create the tables or entity classes and the tool derives the rest, from data-access code to CRUD-based UIs or APIs.
With this in place, it is only natural that the architecture continues to grow around the database. In a traditional N-tier architecture, layers are added on top of the database and dependencies point towards it:
This approach is still heavily employed these days to build new software even though it was conceived many years ago. It’s OK for data-centric systems because modern scaffolding tools do create reliable code, saving you a lot of time and money.
But for systems with complex business rules, this approach often does more harm than good in the medium and long run.
The data-centric architecture focuses on persistence and infrastructure concerns, which heavily influence Design decisions and often times cause business rules to be misplaced. This leads to duplication of business logic, opens breaches for bypassing validations and generates inconsistent data that can’t be trusted.
When the system has grown enough, applying the right techniques to fix these problems becomes expensive; an easy fix is applied instead, wich creates Technical Debt, that accumulates interest and becomes impossible to manage down the road.
Domain is the new King
Domain is the business you’re going to develop software for. It translates to processes and tasks that generate side-effects and produce data.
Now, compare a data-centric system for registering a purchase (inputing sales data) vs an e-commerce system that accepts international payments, has to deal with 2-factor authentication and asynchronous fraud checks, notifies the store about back-ordered products and more. We do have data being generated in both systems but, in the latter, data is just a byproduct.
Since the focus has shifted from the Data to the Domain, we require a change from the Data-driven approach of building software to the Domain-driven approach. This is what DDD, Domain-Driven Design, is about.
Understand the Domain first
When you put the Domain in the center, your first job is to acquire deep knowledge about the business you’re going to work with. You do that by talking to the business people, the domain experts. The purpose of this conversation is NOT to surface requirements or use-cases, but to understand the business problem to be solved, the Domain.
You must forget programming for a moment and strive to gain sufficient knowledge about the Domain as to enable you to use the same language used by the domain experts, to see the problem the same way they do, to understand the need of an automated solution and what is the form of that solution, regardless of technology.
When it does come the time to code, you start by mapping the Domain language: business entities to domain classes and processes to methods. And you create tests early on. This way you can play with a desing built around the Domain; you can implement business rules at the core, without getting distracted by databases and other infrastructure concerns.
The order in which the project rolls out is this:
- Acquire Domain knowledge
- Create Domain classes + tests
- Validate that you have a model that addresses the Domain and the problem at hand
- Iterate until you’re sure
- Then move on to Application code, which orchestrates work among Domain classes
- Only then you actually worry about infrastructure
- Then you can go to UI code
Doing so, your architecture grows naturally in a way that all dependencies point towards the Domain:
Show Me Some DDD Code
DDD is not code. It is a way of thinking, embedded with a set of non-technical recommendations and guidelines that may or may not apply depending on the case. Nevertheless, it most definitely impacts how you write code and structure a project, so here are some examples of how code may be written under the influence of the DDD way of thinking:
Take the Shopping Cart example. It has only a few classes and does not implement any kind of persistence, yet it is a fully encapsulated, functional and unit-tested model that enforces two business rules (no more than 10 units of the same product, minimum of 50 dollars to proceed to checkout) without the need for Service classes or anything like that. And it is impossible to break these rules or misuse the Cart entity in any way that would leave it in an inconsistent or invalid state.
The idea behind this post is just to open your mind about this “new” approach, which has been around for more than a decade, but only recently starts to attract broader attention. I’ve been agressively studying DDD since I first heard about it in January of 2018 and it made me rethink a lot of concepts.
I have changed my way of developing software just as aggressively as I’ve been learning new perspectives, and I can say it has improved my work in quality, delivery-time, number of bugs, customer hapiness, etc.
Here are some articles that carry the DDD way of thinking:
- Why not delete entities
- Domain Services vs Application Services
- Domain Models – Employing the Domain Model Pattern
- Objects should be constructed in one goal
- Fear those Tiers
- DTOs And ViewModels: When And How To Use Them
The ultimate book sources for DDD, in my opinion, are these:
- Domain-Driven Design: Tackling Complexity in the Heart of Software by Eric Evans, also refered to as the Blue Book. This is where DDD starts, but is very theoretical and can be a tough read
- Implementing Domain-Driven Design by Vaughn Vernon. This shows DDD in practice and is a lot easier to grasp
DDD is not an approach for every project, as it is not a silver bullet, but it is very much worth learning and considering.