What is... domain-driven design?
I was just nineteen years old when I heard the term.
I was not even in college. My experience of coding including coding a flakky CMS in PHP by hand, a bit of C++. and a hello world in Java. Oh, and some BASIC on my calculator, for quiz like "what kind of Jedi are you". I knew about OOP, well, the part where your class hierarchy is full of mammals and animals. I also knew a bit about relational databases, enough to know how to do a
SELECT COUNT(*) but not enough to know what a primary key was.
I followed good standard of coding. Like putting all of my member variables in a class
protected, as C++ for dummies told me to do. I wondered why someone would make them private. Make inheritance harder you know. But I knew making them public was bad, because it violated encapsulation. I didn't knew what encapsulation was, but I knew it was a good pratice. You must always follow the good practices.
So one day I heard about ORMs, and how using them made much less painfull interacting with a database. If you ever wrote a website with PHP, you know how painful it can be. So I found a nice little Active Record library, promising me wonders if I used it. No SQL, no endless
$bar.setFoo($result["foo"]); that were so boring to code. But then, as I was reading the library documentation, an odd phrase stuck out.
If you need to have complex objects, ActiveRecord is not the best solution. You are better using Domain-Driven design and cleanly separate data access from your domain objects.
It looked like a good practice, but I didn't understand what it meant. What on earth is a domain? But I remembered the term. Domain-Driven design. For when it is complex. I tucked the concept somewhere in my memory.
A few year later, I had my first real programmer job.
Lets just say... it went very badly.
The software project I worked on crashed and burned, plagued with bugs, delays, costs, and angry customers. As an intern with no prior experience, I was not really at fault. My boss even thanked me for the effort I putted in. Still, I saw what happens when you don't follow good practices. I decided that I would learn to code properly. Remembering that sentence about complexity, I went ahead, and bought the blue book.
Domain-Driven Design, tackling complexity in the heart of software
I think it was my first purchase ever on Amazon. In fact, it was the first time I ever ordered something online. And I read it. I read the blue from beginning to end. But wow, was it ever so hard. The book was full of advices that were completely abstract to me. "Listen to your domain-expert". Who is my domain expert? "Ubiquitous language"? Sure, but to talk with who, exactly? And Eric Evans seemed to be rambling on and on about all this stuff without ever getting to the point.
But then I hit the part were they talked about the patterns.
Value Object. The layers,
At last! Concrete things!
Now that I could understand. Even better, those patterns, they were all good practices! "So," I thought, "If I put my database access code in
Repository, and make my classes extend an
Entity, and I write
Immutable Value Objects, and create all that with
Factories, then all will be good!" I felt that I would finally be able to create complex software that worked. In fact, for me, it seemed so good that of course any kind of software I created should follow these rules. After all, they were all good practices!
So I went ahead, looking around on the internet. I tried to make my software domain-driven. I found some example and tried to follow them. I created
Entities. I created
Repositories. I added a
UI layer, and an
Application layer, and an
Infrastructure layer. And of course, the
Domain layer, which, as I just learned, was the place where most of the job was supposed to happen.
Let just say... it went very badly.
No matter how hard I tried, I could never avoid the Anemic Domain Model. My model was behavior less. And worse, most of my classes seemed to serve no purpose except to shove data between layers. Also, I just couldn't get what the application layer was supposed to do. And some things made no sense.. The domain is supposed to depend on the infrastructure, but repositories are an infrastructure concern? Makes sense in theory, but in practice it feels awkward. Repositories need to know about the domain entity to do their job, but domain objects depend on the infrastructure... where the repositories are.
It didn't work, the good practice weren't helping me! All I could create was overly complex software that only did simple things! And it never seemed, feeled right! How come?
A lot of time has passed since those days. I coded a lot. I worked in a lot of different project, at school, in programming job or just for fun. I read an awful lot of books. I learned how to refactor my code. I learned design patterns, when to use them, when not to use them. I learned TDD. I learned the principle of Clean Code. I learned functional programming. I learned the principle of agile.
I finally understood primary keys, and I learned why members should be private. And I stopped coding in PHP.
And then, I read it again. I reread the blue book.
And somewhere in my mind it clicked. Wow, it clicked so much. I got it. I understood domain-driven design.
Domain driven design is not about
Repositories. Nor about
Entities. It's not about not doing database access in your domain layer. No. The real idea of domain-driven design is not in the patterns. It is in the "rambling" that my younger inexperienced self didn't think was important.
Domain-driven design is about the metaphor. The metaphor. Sure, the book is full of patterns, but they are not what matter. Domain-driven design, can, in fact, be summed up in one sentence.
Build your software so that it is a metaphor of the problem you are trying to solve.
Entity, all of that, they are just tools, tools that you use to write the story of your problem, and the narrative of your solution. What matter is that your class, your variable, any abstraction that you code look and act like it does in the real world. Your code for the domain should be like a picture : capturing the essential details so that you can distinguish what matter.
If you know what a species of flower look like, then you can look at a picture of that flower, and know what it is. This is a rose, this is a picture of a rose. And likewise, if you see picture of a flower, then you can recognize the real flower. Oh, this is lavander, it the first time I see a real one. Drawing is all about capturing the details that matter of a real thing.
You can show a picture of a rose to a botanic expert, and he can tell you, "yes that look like a rose. And this look like a clover and... what is that? lavander?, Lavander don't look like that, lavander is purple", And you learned that lavender is purple. If you correct your drawing, your picture become more and more like real lavander. So you can learn about flowers, by looking at picture of them, and learn what distinguish them. Lavender is purple, rose have torns, clover has three leaves (unless you are lucky today, in which case it has four). Even if the picture is not itself a real flower, you can understand the flower through it.
Of course, if your the one doing the drawing, you need to use a good quality paper. You need to do a rough sketch with a pencil. You need to choose the right ink. But those thing are not about flowers, they are about drawing. They don't allow you to understand the flower better, in fact they get in the way. But they can't go away, they are needed to draw the flower. The true art then, is to draw in such a way that those artefacts fade away, that you don't see a bunch of ink on a sheet of paper, but you see what it represent: a flower. A flower that happen, for the initiated, to be drawn in ink. It could have been drawn in acrylic too. It doesn't matter. What matter is that it look like a flower.
Domain-driven design is about drawing in code. And the abstractions, the classes, the databases, are the ink, paper and pencil used to draw. And the art of domain-driven design is to make them fade away. In a perfect domain-driven application, when you look at the code, you don't see a database, you don't see an MVC app, you don't see a relational database, you see your domain : flowers. Everything seems to be about flowers. You find class like
Pollen. Reading the code may even bring the smell of flowers.
Now it happen that flower species are stored in a relational database, and the flower information is displayed via HTML, but it doesn't matter. What matter is the flowers. The result could be stored in flat file, and the UI could be in Java Swing, it would still be about flowers. The code talk of flowers. The rest is all details, and those details are pushed aside. They fade away to make the flowers stand out
If you know about flower already, and you open one of the class, it's exactly as you expect it to be. A flower object is of a certain species and has a color, and smell something. Reading the code flow naturally. Reading each line, all you can think is "well, of course, duh". You never get lost. Each corner of the application should give a weird feeling of deja vu. Nothing can be a surprise, unless, of course it's something you don't know about flowers.
Immutable Value Object, persistence ignorance... those are like the rule of perspective, the color wheel, the rule of tier. You should use them when it make sense, to draw your domain picture, to tell the domain story. They are tool, guidelines, here to help you.
Respecting those rule does not garantee a good result. A picture of a flower where the subject is on the tier, with perfect color, can still be a crappy flower picture. And a domain-model model full of fat object full of "business logic" and no data-access can be a crappy domain-model. The important is not the rules. The important is the subject of the picture you are drawing. The important is the domain of your application. Again, the important is to put forward the details that matter and to fade away the details that don't
Use the rules, understand the rules, but break them if it make sense, as long as you know why you break them.
Shove your graphics drawing logic in the middle of your entities. Does it make sense? Do you get the application? Is the picture acurate? Does it fit in the domain? Ignore the biggots that yap about good practice. The important is to draw a great picture, the important is to have domain-model that match what the software do. If your domain is about visualization of data, make the visualization first-class citizen in your domain, even if they feel like they should be hidden away in the UI. In fact, give them the prime position. Your software exists to draw visualization, your domain should be about drawing visualization. Yes it's usually a UI concern. Doesn't matter. It's the important detail that you need to put forward. This is what someone coding the application need to think about.
This is what domain-driven design should be. But that not usually what people seem to remember.
If you do (or pretend to do) domain-driven design, I strongly encourage to read the blue book again. What you will see is a lot of example that would make you cringe if you are very religious about good practice. It is not a book about purity or cleanliness. In fact, its one of the most pragmatic book I ever read about software architecture.
Why do people are then so close-minded about those rules, why the rigid view of what a domain-model should be, and how it should be done? Why do I absolutely need fat behavior-heavy objects? Why do I always need to hide anything UI related or persistence related?
Because only thinking about domain-driven design as the patterns is attractive. The pattern are the easy part to understand. They please a programmer mind because they can be explicitely described, remembered. They feel like they can take the hard decision in your place. Reading them is like reading a well defined spec. "Do this, and this and this". You don't have to think. Create entity. Put them in repository. Create them with factory. Separate your UI and your database code. Do all this and you will have a well made software, and it will be easier to work on it.
Well no. All those year ago, it didn't work for me. It didn't made me create awesome software. It only made me create overly complex pile of crap that weren't doing anything.
It's when I stopped caring about domain-driven design that I really started doing domain-driven design. Today, I have software that is choke full of entity and repository and layers and value object, with the database code cleanly separated and a rich object-model. But it's not like that because it's a good practice.
It's like that because I know that this is what let me express a metaphor of my domain the best. I didn't decide to make my abstractions
Value Object. I just sketched their outline in code, capturing the essential detail that matter. Then I inked them with business rules. Its then that they became what they are. The best patterns are the patterns you use without thinking about them.
Do you think that a Domain-Model as no right to know about the database? Or that the only way to code object-oriented is to stuff your class full of behavior, or else it's anemic? If yes, I'll leave you with a question:
If the application you are coding is, let say MySQL workbench. Would it make sense to abstract away in your domain the fact that you connect to a MySQL database?
Think about it.