39. How to shoot yourself in the foot
Design your application starting from the data model
Create your domain model by reverse engineering
Pretend that you’re doing TDD and start testing your domain classes
avanscoper
ta
40. How to shoot yourself in the foot
Design your application starting from the data model
Create your domain model by reverse engineering
Pretend that you’re doing TDD and start testing your domain classes
Particularly getters and setters
avanscoper
ta
41. How to shoot yourself in the foot
Design your application starting from the data model
Create your domain model by reverse engineering
Pretend that you’re doing TDD and start testing your domain classes
Particularly getters and setters
Now start testing the logic with Integration Tests and get stuck by
test data related issues
avanscoper
ta
42. How to shoot yourself in the foot
Design your application starting from the data model
Create your domain model by reverse engineering
Pretend that you’re doing TDD and start testing your domain classes
Particularly getters and setters
Now start testing the logic with Integration Tests and get stuck by
test data related issues
Declare that TDD provides no benefit and only slows you down
avanscoper
ta
43. How to shoot yourself in the foot
Design your application starting from the data model
Create your domain model by reverse engineering
Pretend that you’re doing TDD and start testing your domain classes
Particularly getters and setters
Now start testing the logic with Integration Tests and get stuck by
test data related issues
Declare that TDD provides no benefit and only slows you down
Comment tests in your Build-Integration process
avanscoper
ta
44. How to shoot yourself in the foot
Design your application starting from the data model
Create your domain model by reverse engineering
Pretend that you’re doing TDD and start testing your domain classes
Particularly getters and setters
Now start testing the logic with Integration Tests and get stuck by
test data related issues
Declare that TDD provides no benefit and only slows you down
Comment tests in your Build-Integration process
Keep on whining
avanscoper
ta
45. I won’t reverse engineer my
data model to create a
domain model
46. I won’t reverse engineer my
data model to create a
domain model
I won’t reverse engineer my
data model to create a
domain model
47. I won’t reverse engineer my data
model to create a domain model
I won’t reverse engineer my data
model to create a domain model
I won’t reverse engineer my data
model to create a domain model
48. I won’t reverse engineer my data
model to create a domain model
I won’t reverse engineer my data
model to create a domain model
I won’t reverse engineer my data
model to create a domain model
I won’t reverse engineer my data
model to create a domain model
49. I won’t reverse engineer my data model to
create a domain model
I won’t reverse engineer my data model to
create a domain model
I won’t reverse engineer my data model to
create a domain model
I won’t reverse engineer my data model to
create a domain model
I won’t reverse engineer my data model to
create a domain model
50. I won’t reverse engineer my data model to create a
domain model
I won’t reverse engineer my data model to create a
domain model
I won’t reverse engineer my data model to create a
domain model
I won’t reverse engineer my data model to create a
domain model
I won’t reverse engineer my data model to create a
domain model
I won’t reverse engineer my data model to create a
domain model
110. voilà
!
ORM?
ApplicaEon Services
Remote facade
Commands
Eventually
UI Sp e publish subscribe
cia
l i ze
mo d d a
Remote facade
DTO
?
de l ta
Thin Read Layer
112. do e
voilà s it
!
t o b re
e re a l l y
ORM?
ApplicaEon Services
Remote facade
l at ne e
io n d
a l?
Commands
Eventually
UI Remote facade publish subscribe
DTO
? Thin Read Layer
And that’s the company I started one year ago.
Disclaimer: this is second-hand talk. 99% of the ideas come from these three guys.
In the last couple of years a little revolution has being going on in the DDD community: Udi Dahan (left) and Greg Young (right) have brought new ideas in the DDD landscape.
Ok, let's start from a familiar architecture, what's wrong with that?
Ok, if that’s the answer... If you really like that and think that’s the best possible world... then I don’t have so much to tell you.
On the other hand, if you really think about it, there are a few things in your familiar architecture that you’ve been probably too used to. Enough to forget that there might be a different way.
Let’s try again, with a clear mind.
Here are some of the things we might not like.
Here are some of the things we might not like.
Here are some of the things we might not like.
Here are some of the things we might not like.
Here are some of the things we might not like.
Here are some of the things we might not like.
And here are some of the questions we might ask ourselves
And here are some of the questions we might ask ourselves
And here are some of the questions we might ask ourselves
And here are some of the questions we might ask ourselves
And here are some of the questions we might ask ourselves
And here are some of the questions we might ask ourselves
Ok, let’s start from the anaemic domain model: in the picture red is where the logic is. As you might see, there’s not so mouch in the Order class...
How did we get there? Well sometimes it’s just a matter of features that came for free, like a tool that allows you to reverse engineering your database to create domain classes.
Ok, but anaemic domain model is probably the dominant pattern throughout the world, so it must have some advantages: let’s dig into them.
Ok, but anaemic domain model is probably the dominant pattern throughout the world, so it must have some advantages: let’s dig into them.
Ok, but anaemic domain model is probably the dominant pattern throughout the world, so it must have some advantages: let’s dig into them.
Let’s look at the drawbacks instead... in two words it provides all the architetural complexity of an OOP system with the advantages in maintenance of a procedural one. :-P
Let’s look at the drawbacks instead... in two words it provides all the architetural complexity of an OOP system with the advantages in maintenance of a procedural one. :-P
Let’s look at the drawbacks instead... in two words it provides all the architetural complexity of an OOP system with the advantages in maintenance of a procedural one. :-P
Let’s look at the drawbacks instead... in two words it provides all the architetural complexity of an OOP system with the advantages in maintenance of a procedural one. :-P
So what should we do instead?
So what should we do instead?
So what should we do instead?
So what should we do instead?
So what should we do instead?
So what should we do instead?
So what should we do instead?
So what should we do instead?
I think this is a really sensible resolution :-)
... you got the point ;-)
Let’s try to be a little more constructive
For example, Mr. Eric Evans has something really interesting to say about how should we implement a Domain Model:
For example, Mr. Eric Evans has something really interesting to say about how should we implement a Domain Model:
For example, Mr. Eric Evans has something really interesting to say about how should we implement a Domain Model:
For example, Mr. Eric Evans has something really interesting to say about how should we implement a Domain Model:
For example, Mr. Eric Evans has something really interesting to say about how should we implement a Domain Model:
What does it mean to “put behaviour in the domain model”? Here is our starting point: all the logic is in the service class.
In a “Rich” Domain Model (I really don’t know why is Rich vs Anaemic, maybe “bloody domain model” or “poor domain model” weren’t ok for the job) le logic is “where it belongs” according to Single Responsibility Principle (Martin) or Information Expert (Larman).
It’s not spread equally... Customer doesn’t do much, while Money for example looks like a pure data type, but has a lot of math-related behaviour in it.
Interestingly, TDD and DDD form a perfect match: DDD needs TDD for many of the key practices, while TDD naturally enforces DDD-like coding styles.
It’s just perfect.
The next key DDD building block is Aggregates. The Domain Model isn’t flat. Some links are stronger than others (and UML doesn’t really help much in rendering it).
If we start considering consistency and behaviour as the primary drivers for modeling our domain we’ll end up with something quite different from a 1-1 projection of the data model.
The next key DDD building block is Aggregates. The Domain Model isn’t flat. Some links are stronger than others (and UML doesn’t really help much in rendering it).
If we start considering consistency and behaviour as the primary drivers for modeling our domain we’ll end up with something quite different from a 1-1 projection of the data model.
For example, in this case we’ll notice some duplication, related to customer. But lifecycles of the customer and of the order are different. If a customer moves, we don’t want to have all of our past orders changed, at the same time if an order needs to be canceled, we don’t want the user to get down the sink as well.
A little duplication is what allows aggregate lifecycles to be independent.
Some data-driven analyst are probably really good in spotting these problems just out of their experience.
But really, this part of modeling is our everyday work, and should be easy as walking back home in a sunny day.
Shouldn’t really have to rely on the experience of some rarely available guy that knows all the traps and hidden perils of data modeling.
But here’s something to think about: this modeling style enforces loose coupling between aggregates. As a side effect, queries tend to be a lot simpler and focused. In many situations, this opens the door for some alternative persistence strategy.
Ok, so let’s see how DDD can improve our application architecture.
Not so many things are happening at the service layer, just basic coordination.
Bounded contexts are enforced, and aggregate boundaries within them.
But other portions of the architecture don’t change that much.
... is there anything else that we can do?
Not so many things are happening at the service layer, just basic coordination.
Bounded contexts are enforced, and aggregate boundaries within them.
But other portions of the architecture don’t change that much.
... is there anything else that we can do?
Not so many things are happening at the service layer, just basic coordination.
Bounded contexts are enforced, and aggregate boundaries within them.
But other portions of the architecture don’t change that much.
... is there anything else that we can do?
Not so many things are happening at the service layer, just basic coordination.
Bounded contexts are enforced, and aggregate boundaries within them.
But other portions of the architecture don’t change that much.
... is there anything else that we can do?
Not so many things are happening at the service layer, just basic coordination.
Bounded contexts are enforced, and aggregate boundaries within them.
But other portions of the architecture don’t change that much.
... is there anything else that we can do?
Not so many things are happening at the service layer, just basic coordination.
Bounded contexts are enforced, and aggregate boundaries within them.
But other portions of the architecture don’t change that much.
... is there anything else that we can do?
Using DO in the UI seemed like a good idea (I confess I hated the abuse of DTOs so much that I tried it myself), but then you run into objects which are potentially inconsistent.
A common solution is to have every DO in 2 possible states: valid and invalid, and valid state must be enforced before any business method is invoked on the object. So why not make it mandatory, with aspects or template method pattern. Why not make this solution available/mandatory to all the domain classes? ... well ...No.
Using DO in the UI seemed like a good idea (I confess I hated the abuse of DTOs so much that I tried it myself), but then you run into objects which are potentially inconsistent.
A common solution is to have every DO in 2 possible states: valid and invalid, and valid state must be enforced before any business method is invoked on the object. So why not make it mandatory, with aspects or template method pattern. Why not make this solution available/mandatory to all the domain classes? ... well ...No.
Using DO in the UI seemed like a good idea (I confess I hated the abuse of DTOs so much that I tried it myself), but then you run into objects which are potentially inconsistent.
A common solution is to have every DO in 2 possible states: valid and invalid, and valid state must be enforced before any business method is invoked on the object. So why not make it mandatory, with aspects or template method pattern. Why not make this solution available/mandatory to all the domain classes? ... well ...No.
Using DO in the UI seemed like a good idea (I confess I hated the abuse of DTOs so much that I tried it myself), but then you run into objects which are potentially inconsistent.
A common solution is to have every DO in 2 possible states: valid and invalid, and valid state must be enforced before any business method is invoked on the object. So why not make it mandatory, with aspects or template method pattern. Why not make this solution available/mandatory to all the domain classes? ... well ...No.
Using DO in the UI seemed like a good idea (I confess I hated the abuse of DTOs so much that I tried it myself), but then you run into objects which are potentially inconsistent.
A common solution is to have every DO in 2 possible states: valid and invalid, and valid state must be enforced before any business method is invoked on the object. So why not make it mandatory, with aspects or template method pattern. Why not make this solution available/mandatory to all the domain classes? ... well ...No.
Using DO in the UI seemed like a good idea (I confess I hated the abuse of DTOs so much that I tried it myself), but then you run into objects which are potentially inconsistent.
A common solution is to have every DO in 2 possible states: valid and invalid, and valid state must be enforced before any business method is invoked on the object. So why not make it mandatory, with aspects or template method pattern. Why not make this solution available/mandatory to all the domain classes? ... well ...No.
Ok, question for the audience: two Stories, hitting different portions of the application, triggered by the same external event.
How would you model them? I must admit that in a similar situation I spent some time wondering: “Is it better to have order.purchase(customer, ...) or customer.purchase(order, ...)?” or many other variation on the theme.
That’s the very specific Greg Young’s definition. I like it.
Domain Events as a communication means between aggregates really simplify things a lot, even at the conceptual level.
- Do they really belong to the same transaction?
- Would you want the order to roll-bak if you are unable to process the discount for the next order bu the same customer?
... but really, how the two things should be related, is a business choice! We just have more and more possibilites in our arsenal.
There’s been a never ending debate in the SOA community (and many dollars and euros wasted) about “service granularity”. A good read of the blue book could have helped a lot, the solution was already there...
Let’s start to bite something bigger
Which one is the right shoe for you?
Well ...it depends :-) each one serves a particular use. We change shoes according to what we want to do.
So why should we have only one architecture?
CQS existed before DDD and was part of the DDD toolkit collection, basically at the class design level. It really enhances scalability and maintainability.
But CQRS promotes the same concept at the architectural level. Commands and quesries have different needs.
When we ask, there is generally no behavior involved. Just data.
So one first step might be to evolve the “classical” DDD architecture...
... into something more specialized: the domain model is used only in the command side, while the query side is definitely thinner.
Let’s dive into the query side. Udi Dahan pointed out that sometimes the biggest source of optimization is to have a look at what the users are really doing: capturing user intent might surprise you.
Also, the fact that we can sometimes provide real time data, doesn’t really mean that we must alway provide them. Most of the time a little of delay is absolutely acceptable.
Sometimes requirements are not even coming from the business, it’s just IT people showing off...
Wow, that is a kind of shock for DDD zealots. Objects are there for the behavior. The domain model is an efficient way to represent behavior. If there’s no behavior then there’s no real need for objects as well.
Did I mention that we could get rid of some of our assumptions? ;-)
How would you optimize a Query Only architecture?
- we could just use some of the tools vendor provide us to manage straight data.
- we could have a specialized model for the view, with different table structure, eventually updated by a background process.
- ... and many other cool ideas!
Also, even stale data could be a great help in managing pleliminary validation of the commands. We can still perform validation on the presentation layer and make sure that most of the commands simply won’t fail.
Let’s see the consequences on the command side. More trust means less burden, and a little less synchronicity, meaning less load.
Commands are a lot closer to user intent. It’s not just editing data. Is ding it with a purpose.
... so why should show entities in the presentation layer?
The domain model turns out to become even simpler: it’s write only. Classes are always in a consistent state and a command issued to the class, triggers an action and/or a state transition. Just that.
Let’s get back to the gorilla... what do we need to persist? and How? What’s the most efficient strategy for persisting a domain model?
Let’s shake things a little bit more :-)
The next little revolution is to have 2 different persistence storage: one optimized fopr working with the domain model? the other one optimized for the Query Only model. The two are eventually consistent.
Just think about how many locking issues are blown away by separating the two...
The next little revolution is to have 2 different persistence storage: one optimized fopr working with the domain model? the other one optimized for the Query Only model. The two are eventually consistent.
Just think about how many locking issues are blown away by separating the two...
The next little revolution is to have 2 different persistence storage: one optimized fopr working with the domain model? the other one optimized for the Query Only model. The two are eventually consistent.
Just think about how many locking issues are blown away by separating the two...
The next little revolution is to have 2 different persistence storage: one optimized fopr working with the domain model? the other one optimized for the Query Only model. The two are eventually consistent.
Just think about how many locking issues are blown away by separating the two...
Objects are tiny now. No collections, no mapping. Intersting things might happen...
Surprisingly, but Udi Dahan and Greg Young in their speeches at last DDDx put the paper-based system at the center of their concern. If a complex system could work without computers ...there must be a reason for that. Some times computers just loeded the systems with more unnecessary complexity.
Let’s now face another assumption...
You might also want to have a look to Alistair Cockburn exagonal architecture, you might find quite a few similarities in the problem setting.
There might be inconsistencies in the data or between the data and the paper. In many system (especially those data-entry based) the paper used to be the Single Source of Truth, but larger integrated systems Events are probably a better candidate.
There might be inconsistencies in the data or between the data and the paper. In many system (especially those data-entry based) the paper used to be the Single Source of Truth, but larger integrated systems Events are probably a better candidate.
So Events are passing from the command side to the Query side in a publish-subscribe fashion, they need to ba made persistent as well
In such a model, what’s the best way to model an entity? Our aggregates are receiveng entities and updating state, can we achieve the same result with a more efficient strategy?
The Specification pattern turns out really useful for that, but also note that entities are a little less mutable than they used to be.
This might be a blast! Think about the amount of opportunities
Ok, this one is a picture I really like, and reuse over and over...
DDD has a lot to do with learning. But Event sourcing is a learning tool as well! Only, stop assuming that Business People know everything about the business, there’s a lot more to learn for them also! Why not doing it together?
Surprisingly, googling “land of opportunity” leads to Arkansas. But I like this picture... :-)
One important lesson: you don’t need all of this at once. But every little step brings an improvement, and it’s worth taking.
despite how cool this stuff looks ...be pragmatic.