There are a lot of materials how to model Aggregates and Entities in Domain Driven Design. There are also a lot of materials how to manage your Event Stores, when you are applying Command Query Responsibility Segregation with Event Sourcing. And definitely there are a lot of materials how to combine those ideas together.
However, I cannot find any articles about the way that developer’s mindset (and his code) is being changed when he tries to leave the Anemic Domain approach and goes into the deep with all the concepts mentioned above.
So let’s take a closer look at it. I will provide an example and try to depict how my mindset was changed when I was adding new things to my code. I will use a very simple domain and model it in the easiest possible way, so as not to obscure the picture.
This is the first article out of four that I will write in the nearest future, so stay tuned.
One can debate if my approach to modeling the domain is the best, but for this series, I think, is good enough. ;)
Let’s
think for a moment about very simplified domain for a football match.
For you guys – on the other side of the ocean – it's... ...still a football match
(it's not a soccer - deal with it!). ;)
We have two teams that will play the match. We don’t know the date of the match at the moment of defining it, but we know which teams will play against each other. We can later setup the match date, but it can be done only until the match is finished. We can once finish the match with a score, but it cannot be finished before its start.
The end user wants to see the match: team names that play, match date if is set, match finish date and score if match was finished.
How would You start to model this domain?
Stop here for a moment and imagine you are the person which is about to do this.
Before you continue reading, try to answer those simple questions below. Try to catch your first thoughts and then, compare them with my approach.
The first thing that comes to mind for experienced developer - who doesn’t know how fancy things can be ;) – is to create Anemic Entities mapped with Hibernate and a Service for managing them. It can be something like this:
As we can see, we have quite normal, classic Anemic Entities with private fields and public setters/getters. They are ruled by the MatchService and we can pray that nobody else will modify their fields from other places in the system...
We have even some @ManyToOne annotations that join our Matches with Teams.
We also have probably some Unit Tests for the Service that will check if correct fields are set during service method calls, and if exceptions are thrown correctly. It’s far less likely, that we will have Unit Tests checking if fields that we don’t want to set, are actually not set during those invocations, but who would care… Right? ;)
As you can imagine, this approach can work perfectly fine. There are A LOT of services modeled in this manner and they are profitable.
However, I think that after some time, without changing the mindset, the code above can be modified so many times, that it will become simply unreadable. The service implementation can have even thousands of lines. There is so much implicity inside, that in a moment there can be no one, who will understand the model.
In upcoming posts I will try to change this code, step by step, to make it more explicit and more maintainable.
So how about your model? Is it similar?
Changing the mindset series:
However, I cannot find any articles about the way that developer’s mindset (and his code) is being changed when he tries to leave the Anemic Domain approach and goes into the deep with all the concepts mentioned above.
So let’s take a closer look at it. I will provide an example and try to depict how my mindset was changed when I was adding new things to my code. I will use a very simple domain and model it in the easiest possible way, so as not to obscure the picture.
This is the first article out of four that I will write in the nearest future, so stay tuned.
One can debate if my approach to modeling the domain is the best, but for this series, I think, is good enough. ;)
The example domain
We have two teams that will play the match. We don’t know the date of the match at the moment of defining it, but we know which teams will play against each other. We can later setup the match date, but it can be done only until the match is finished. We can once finish the match with a score, but it cannot be finished before its start.
The end user wants to see the match: team names that play, match date if is set, match finish date and score if match was finished.
How would You start to model this domain?
Stop here for a moment and imagine you are the person which is about to do this.
Before you continue reading, try to answer those simple questions below. Try to catch your first thoughts and then, compare them with my approach.
- How would you start?
- What would be the first thing that you model out?
- How would it be related to the database?
- How would you model user actions that can be taken?
- Would you even care about it when modeling the domain?
The Anemic Model
The first thing that comes to mind for experienced developer - who doesn’t know how fancy things can be ;) – is to create Anemic Entities mapped with Hibernate and a Service for managing them. It can be something like this:
@Entity @Table(name=”teams”) public class Team { @Id private String name; // getters + setters } @Embeddable public class Score { @Basic private int homeGoals; @Basic private int awayGoals; // getters + setters } @Entity @Table(name=”matches”) public class Match { @Id @Type(type="org.hibernate.type.UUIDCharType") private UUID id; @Column(updatable=false, insertable=false) private String homeTeamId; @ManyToOne private Team homeTeam; @Column(updatable=false, insertable=false) private String awayTeamId; @ManyToOne private Team awayTeam; @Basic private Date matchDate; @Basic private Date finishDate; private Score score; // getters + setters } public interface MatchService { void createMatch(UUID matchId, String homeTeamId, String awayTeamId); void setupMatchDate(UUID matchId, Date matchDate) throws MatchAlreadyFinishedException; void finishMatchWithScore( UUID matchId, int homeGoals, int awayGoals, Date finishDate) throws MatchFinishedBeforeStartException, MatchAlreadyFinishedExcepion; }
As we can see, we have quite normal, classic Anemic Entities with private fields and public setters/getters. They are ruled by the MatchService and we can pray that nobody else will modify their fields from other places in the system...
We have even some @ManyToOne annotations that join our Matches with Teams.
We also have probably some Unit Tests for the Service that will check if correct fields are set during service method calls, and if exceptions are thrown correctly. It’s far less likely, that we will have Unit Tests checking if fields that we don’t want to set, are actually not set during those invocations, but who would care… Right? ;)
It still works
As you can imagine, this approach can work perfectly fine. There are A LOT of services modeled in this manner and they are profitable.
However, I think that after some time, without changing the mindset, the code above can be modified so many times, that it will become simply unreadable. The service implementation can have even thousands of lines. There is so much implicity inside, that in a moment there can be no one, who will understand the model.
In upcoming posts I will try to change this code, step by step, to make it more explicit and more maintainable.
So how about your model? Is it similar?
Changing the mindset series:
- Changing the mindset - part 1 / 4 - Classic approach
- Changing the mindset - part 2 / 4 - Modeling the Domain
- Changing the mindset - part 3 / 4 - Segregation of Responsibility
- Changing the mindset - part 4 / 4 - Subtle difference
Comments
Post a Comment