I find it kidna funny that we say that "classical layered approach" can work for small projects and then we try to show benefits of DDD on the same small examples. But sometimes (quite often) in big systems we choose verbosity to provide better clarity and reduce coupling. To me it was terrifying what happened to our domain by the end of the presentation.
00:00 - 04:22 Introduction 04:23 - 04:58 What is DDD? 04:58 - 06:08 What does DDD mean for developers: Understanding the domain. 06:08 - 06:32 What does DDD mean for developers: Split big domains into subdomains. 06:32 - 08:00 What does DDD mean for developers: Develop an ubiquitus languages. 08:00 - 08:35 What does DDD mean for developers: Develop a domain model + separate domain model from implementation details. 08:35 - 09:24 The Old Testament and the New Testament. 09:28 - 13:20 What is the domain model: introduction. 13:40 - 16:23 Existing Library Software: anemic domain anti-pattern. 16:24 - 17:14 Why we don't want this approach. 17:24 - 20:02 DDD Library: User Stories and what they tell us. 20:02 - 20:42 DDD Library: Implementation start. 20:42 - 25:20 DDD Library: Creating the domain model. 25:20 - 26:40 DDD Library: JPA vs separate domain models. 26:40 - 30:15 DDD Library: adapting domain model to work with JPA (@Embedded and @EmbeddedId). 30:15 - 33:27 DDD Library: Creating the Copy class and a note on @ManyToOne in DDD (31:24). 33:27 - 37:00 DDD Library: implementing the use-cases, the wrong way. 37:00 - 39:53 DDD Library: implementing the use-cases, the correct way using dependency inversion. 39:53 - 41:30 DDD Library: Service Taxonomy using custom Java @Annotations. 41:30 - 45:07 DDD Library: Bounded Context #2 Lending books. 45:08 - 46:03 Enforcing module separation using Modulith tests. 46:04 - 48:50 What if some modules need to depend on eachother? Solution: extend AbstractAggregateRoot and work event driven. 48:51 - 50:17 Outro.
I think what we usually did was to create a BookEntity class in the infra layer and together with Mapper classes(that maps domain object to corresponding database entity object), this way we separate the domain object definitions from the database variations of it according to the onion architecture's separation of concerns
The code will look much better once we replace JPA with Spring Data: it supports immutable entity classes out of the box, it kinda forces identifying aggregates.
I found the idea of coding the implementation as userstories / usecases extremely insightfull, seeems to work really well with ddd. Goes hand in hand with good architecture documentation and requirements engineering and is pretty good from a perspective as "code as documentation". Never thought of this. Its roughly at timecode 34:30
I feel this approach a bit confusing especially when you pass repository into the domain entity. What can be more straightforward than having 3 main layers (Controller, Services, Repositories). In real life scenarios, there might be a lot of communication with different systems, so putting all that logic in service layer looks more reasonable for me. And basically these UseCase classes could be in fact small granular services e.g. AddBookToCatalogService.
That’s just upgrading the old MVC to MCV 2.0 (with Trushtero services) With this approach you are going to really take care of the business domain and clean architecture
Can't say I liked it. In the very beginning we say, that our domain should be framework agnostic and yet we introduce jpa entities right into it. Next we implement BookSearchService in infrastructure. Oh wait, let's just put it in application package just because that's the rule. What is the difference between infrastructure and application then? When creating Loan domain, we introduce LoanRepository argument into its constructor. Why? And there's much more I don't get about it. In the end, even if somehow manage to understand it, how am I supposed to explain it to the others.
The repository call in the domain object even does not guarantee the rule is not broken, because it's not transactional consistent... I think no-one should do something like that. There is a lack of some Availability concept in the domain.
record BookId(UUID) record ISBN(String) .... These wrappers create more tasks for the GC. I'm waiting for the day when the Java compiler supports new type/opaque type like the Scala compiler (i.e. we still have BookId and ISBN but the compiler will remove them while still keeping all the validations inside them).
Thanks for this talk, very informative. For creating an audit trail of a user, would events, or Aspect be prefered ? It seems that with spring modulith we can achieve the same result of using Aspect. If we use events we can even have a module audit, and have the audit persistence and reading of such decoupled
If one uses jpa entity classes that need mapping to domain objects there will be quite so code gymnastics to lazy load collections because mapping them will always result in an eager fetch
so all the control/validation/restrictions/events will be in an Entity/POJO, services and business layers are empty :/ ... you manage the entire flow of a project by the actions performed against "the domain"
There is something codesmell I think. Domain layer should be written as pure as possible. Repository definition and entity definitions violate something here.Tests of the domain layer should also be written independently. But there is JPA dependency here.
Nice talk. Just one question, in the BookSearchService takes an Isbn as parameter, but the Isbn type is defined in domain layer but used in the app and infrastructure layer. Would passing a String representation of a isbn sufficient ?
It’s absolutely fine as any of these “layers”/“modules” can use domain classes. That’s the whole purpose of the design: keep the domain module pure and clean, and have all the rest of the application to use that domain to actually get a working application.
@@roman-proshin Oh ok I have never thought of it that way. So there is no mapping to a DTO needed when returning an entity from the domain to a Restful request ?
Interesting but Domain driven design I still don't get the benefits on micro services at least. A lot of classes and complexity. Yes small classes are simpler to maintain. Anyway I will continue the journey with the videos you mentioned.
Just my 2 cents DDD is a design pattern specifically for somewhat complex to complex business domains. If you're doing scripting or building small apps that don't have tons of complex business logic and entities than best to stick with what you know. However if you're working with a complex business domains DDD really shines and shows you how badly you've been building software lol. Like imagine a freight shipping company that deals with delivers packages internationally. There are tons of different laws you may have to deal with from different countries in a single trip. Between that and varying currencies, delays, timezones etc you could imagine there's tons and tons of "tribal knowledge" that the business users know about how it all works that's probably not really documented anywhere. So when building software for those people to solve a problem they have, it's important that you model your software correctly so it doesn't implode as things change and code needs to be modified/extended. Writing the code is almost secondary, design and understanding your users domain space is primary. Hope this helps
Implementing DDD chapter 1 has some guidance on answering this question. If you start talking to a domain expert to try to understand the problem and you keep finding caveats (i get concerned after 3-5 branches down a certain process pipeline), it is time to go back and apply DDD more formally. But you should consult the book for a more holistic answer because every domain is different. But if it is complex to you and your customer, it is probably complex.
In my opinion, the domain shouldn't know anything about how the entity will be saved, updated or whatever, and where it would happen. For the domain it should be an abstraction. For example, you can decide not to use JPA, and use JDBC instead. And if you're designed your application correctly, you won't change anything in domain module, you won't even recompile it, and only persistence module will be changed. And modulith only help you design you monolith application, not microservice with DDD. But gradle can, since for each module (presentation, persistence, use cases, domain) you can set it's own dependencies. And, for example, domain will never depend on use cases, and you can even write tests for that. And you don't even need to recompile inner modules, when you change anything in outer modules.
Indeed, your vision or your approach is correct. In addition, I noticed that there are two architectural approaches to doing DDD. Obviously the one you described above, and the one he presents in his talk based on Spring Data JDBC (AggregateRoot) using JPA annotations. Your approach is ideal since it avoids a decoupling between the business domain and the infrastructure layer, however it requires a lot of DTO. In short, note that the DDD approach is a free approach, since it is based on a set of good practices (TDD, BDD, CLEAN ARCHI and others). But does not define any specific architecture. Personally I recommend using the one that will allow you to deliver your software faster
@@rolandjost3823 Fast Delivery in this way normally implies slowing maintenance in the future. I don't know if everything is valid just for Fast Delivery...
If you have an interface which exposes save function and it is implemented in infrastructure layer, then the domain will never know how something is persisted or which is the underlying technology, this is exactly what was demonstrated here.
@@Boss-gr4jw Nope. He used annotation "Entity" and to use it as a JPA entity he made domain "Entity" mutable, created no arg constructor for JPA and so on. So, your domain module already knows what technology will be used. data-JDBC, for example, doesn't need any of this staff.
Great talk, but still don't see any chance to use this in real world biz logic. For example: It do valid in domain object, but what if I got a new requirement that I need bypass or add some valid in some biz logic? It seems hard to do this new task. Instead, with old school POJO way, it's easy.
The problem with keeping the data model with the domain model is a problem with java and spring. C# with dotnet solves the problem in an much elegant way. This makes C# a go to framework when thing about DDD. U should alway keep your domain model free from any infastructure concerns. Unfortunately spring jpa makes such aproach look like a boilerplate. Is this not a violation of the single responsibility principles?
Another year, another 'shiny concept'. Seems like this one is going to take us back to monoliths with the addition of confusion of what 'domain driven design' is. Seems like its someone else's turn in the spotlight to sell books and courses. I note hardly anyone talks about having a multi-module spring project e.g. multi-module Maven to decompose an application into. A lot less confusing than trying to introduce yet another concept/buzz-phrase/buzz-idea.
This might looks fancy but In my work experience, this way of modeling microservice is worst thing you can do in fast developing world. I want my developers to get features out as fast as possible with proper testing. I don't want them to waste time in managing packages. controller, service, entities, repositories, util, helper. with No shitty one interface, one class thing. just keep it simple !! You are not gonna need it.
One interface is good. You have a list of use cases in one place. I think they used to call it a facade :) If needed, implementation can be split into classes
That's how you end up with the anemic model and god classes which are impossible or hard to test. Also you end up putting functions together into services which are not related at all. This all results in so fragile code, hard to change, every change requires full recompilation of unrelated classes, slow builds, slow tests etc. There is a reason for why you should be designing into interfaces and smaller classes and packages. For very small service there is no reason not to put everything into same package, if it really is small.
this approach intend isn't for simple projects or APIs (for that u can still use plain MVC), when a project grows and this involves scaling in complexity, let say after 1.5 year aprox, when more business rules are added if you don't have a Clean Architecture then u'll find out that the code is a mess and highly coupled, then making adaptations among business rules look really dirty in legacy approaches. Making code as faster as possible is the opposite of making high quality code (I prefer having code well organized and tested that can adapt in the future easily than writting fast code for a user story than will be broken in the near future)
I find it kidna funny that we say that "classical layered approach" can work for small projects and then we try to show benefits of DDD on the same small examples.
But sometimes (quite often) in big systems we choose verbosity to provide better clarity and reduce coupling.
To me it was terrifying what happened to our domain by the end of the presentation.
00:00 - 04:22 Introduction
04:23 - 04:58 What is DDD?
04:58 - 06:08 What does DDD mean for developers: Understanding the domain.
06:08 - 06:32 What does DDD mean for developers: Split big domains into subdomains.
06:32 - 08:00 What does DDD mean for developers: Develop an ubiquitus languages.
08:00 - 08:35 What does DDD mean for developers: Develop a domain model + separate domain model from implementation details.
08:35 - 09:24 The Old Testament and the New Testament.
09:28 - 13:20 What is the domain model: introduction.
13:40 - 16:23 Existing Library Software: anemic domain anti-pattern.
16:24 - 17:14 Why we don't want this approach.
17:24 - 20:02 DDD Library: User Stories and what they tell us.
20:02 - 20:42 DDD Library: Implementation start.
20:42 - 25:20 DDD Library: Creating the domain model.
25:20 - 26:40 DDD Library: JPA vs separate domain models.
26:40 - 30:15 DDD Library: adapting domain model to work with JPA (@Embedded and @EmbeddedId).
30:15 - 33:27 DDD Library: Creating the Copy class and a note on @ManyToOne in DDD (31:24).
33:27 - 37:00 DDD Library: implementing the use-cases, the wrong way.
37:00 - 39:53 DDD Library: implementing the use-cases, the correct way using dependency inversion.
39:53 - 41:30 DDD Library: Service Taxonomy using custom Java @Annotations.
41:30 - 45:07 DDD Library: Bounded Context #2 Lending books.
45:08 - 46:03 Enforcing module separation using Modulith tests.
46:04 - 48:50 What if some modules need to depend on eachother? Solution: extend AbstractAggregateRoot and work event driven.
48:51 - 50:17 Outro.
I say Really thank you.
I think what we usually did was to create a BookEntity class in the infra layer and together with Mapper classes(that maps domain object to corresponding database entity object), this way we separate the domain object definitions from the database variations of it according to the onion architecture's separation of concerns
The code will look much better once we replace JPA with Spring Data: it supports immutable entity classes out of the box, it kinda forces identifying aggregates.
I found the idea of coding the implementation as userstories / usecases extremely insightfull, seeems to work really well with ddd. Goes hand in hand with good architecture documentation and requirements engineering and is pretty good from a perspective as "code as documentation". Never thought of this.
Its roughly at timecode 34:30
25:27 DDD code review.
- You don’t need to RE-validate the ISBN value object.
- Domain coupled to infrastructure (framework)
- Domain coupled to infrastructure (framework). This is bullshit. Java got to fix this and have a better way to deal with this.
I feel this approach a bit confusing especially when you pass repository into the domain entity. What can be more straightforward than having 3 main layers (Controller, Services, Repositories). In real life scenarios, there might be a lot of communication with different systems, so putting all that logic in service layer looks more reasonable for me. And basically these UseCase classes could be in fact small granular services e.g. AddBookToCatalogService.
That’s just upgrading the old MVC to MCV 2.0 (with Trushtero services)
With this approach you are going to really take care of the business domain and clean architecture
This talks is excellent and it has been featured in the last issue of Tech Talks Weekly newsletter 🎉
Congrats Maciej!
Finally, I have been waiting for the video to be uploaded.
Can't say I liked it. In the very beginning we say, that our domain should be framework agnostic and yet we introduce jpa entities right into it.
Next we implement BookSearchService in infrastructure. Oh wait, let's just put it in application package just because that's the rule. What is the difference between infrastructure and application then?
When creating Loan domain, we introduce LoanRepository argument into its constructor. Why?
And there's much more I don't get about it. In the end, even if somehow manage to understand it, how am I supposed to explain it to the others.
The repository call in the domain object even does not guarantee the rule is not broken, because it's not transactional consistent...
I think no-one should do something like that. There is a lack of some Availability concept in the domain.
Clear and detailed. Thank you for the efforts!
record BookId(UUID)
record ISBN(String)
....
These wrappers create more tasks for the GC. I'm waiting for the day when the Java compiler supports new type/opaque type like the Scala compiler (i.e. we still have BookId and ISBN but the compiler will remove them while still keeping all the validations inside them).
If you start to carry about java GC optimisations like this, you probably need to get rid of all "spring-data" and lots of other stuff first.
very nice and informative talk
what is the difference betwen service and use case
Why is Book an entity and not a VO in the catalog domain ?
Thanks for this talk, very informative.
For creating an audit trail of a user, would events, or Aspect be prefered ? It seems that with spring modulith we can achieve the same result of using Aspect. If we use events we can even have a module audit, and have the audit persistence and reading of such decoupled
nice presentation, mr. homelander
Thanks for the presentation! Is a repository of non-DDD example of library available somewhere?
Perfect talk, enjoyed it a lot
If one uses jpa entity classes that need mapping to domain objects there will be quite so code gymnastics to lazy load collections because mapping them will always result in an eager fetch
so all the control/validation/restrictions/events will be in an Entity/POJO, services and business layers are empty :/ ... you manage the entire flow of a project by the actions performed against "the domain"
There is something codesmell I think. Domain layer should be written as pure as possible. Repository definition and entity definitions violate something here.Tests of the domain layer should also be written independently. But there is JPA dependency here.
I thought that the combination of @Entity and @Data is discouraged.
Nice talk. Just one question, in the BookSearchService takes an Isbn as parameter, but the Isbn type is defined in domain layer but used in the app and infrastructure layer. Would passing a String representation of a isbn sufficient ?
It’s absolutely fine as any of these “layers”/“modules” can use domain classes. That’s the whole purpose of the design: keep the domain module pure and clean, and have all the rest of the application to use that domain to actually get a working application.
@@roman-proshin Oh ok I have never thought of it that way. So there is no mapping to a DTO needed when returning an entity from the domain to a Restful request ?
@@dimitricharles9784 No. Use DTOs only when necessary
Interesting but Domain driven design I still don't get the benefits on micro services at least. A lot of classes and complexity. Yes small classes are simpler to maintain.
Anyway I will continue the journey with the videos you mentioned.
ummm i've read in a lot of places about how bad is uuid like a id in database, it aint sortable and the index may be messy
After watching this video, it feels like my 7 years of experience was a lie. It is so tough to implement by ourselves.
Nice talk. Thanks.
Can DDD be employed to develop any type of software of is this peculiar to certain type of softwares?
Just my 2 cents DDD is a design pattern specifically for somewhat complex to complex business domains. If you're doing scripting or building small apps that don't have tons of complex business logic and entities than best to stick with what you know. However if you're working with a complex business domains DDD really shines and shows you how badly you've been building software lol. Like imagine a freight shipping company that deals with delivers packages internationally. There are tons of different laws you may have to deal with from different countries in a single trip. Between that and varying currencies, delays, timezones etc you could imagine there's tons and tons of "tribal knowledge" that the business users know about how it all works that's probably not really documented anywhere. So when building software for those people to solve a problem they have, it's important that you model your software correctly so it doesn't implode as things change and code needs to be modified/extended. Writing the code is almost secondary, design and understanding your users domain space is primary. Hope this helps
Implementing DDD chapter 1 has some guidance on answering this question. If you start talking to a domain expert to try to understand the problem and you keep finding caveats (i get concerned after 3-5 branches down a certain process pipeline), it is time to go back and apply DDD more formally. But you should consult the book for a more holistic answer because every domain is different. But if it is complex to you and your customer, it is probably complex.
normal people at 5 am: sleeps
devs at 5 am: watches this video
I just woke up at 5:00am to watch this. It's 5:08am now.
Mixing domain and framework. Nice
In my opinion, the domain shouldn't know anything about how the entity will be saved, updated or whatever, and where it would happen.
For the domain it should be an abstraction.
For example, you can decide not to use JPA, and use JDBC instead. And if you're designed your application correctly, you won't change anything in domain module, you won't even recompile it, and only persistence module will be changed.
And modulith only help you design you monolith application, not microservice with DDD. But gradle can, since for each module (presentation, persistence, use cases, domain) you can set it's own dependencies. And, for example, domain will never depend on use cases, and you can even write tests for that. And you don't even need to recompile inner modules, when you change anything in outer modules.
Indeed, your vision or your approach is correct. In addition, I noticed that there are two architectural approaches to doing DDD. Obviously the one you described above, and the one he presents in his talk based on Spring Data JDBC (AggregateRoot) using JPA annotations.
Your approach is ideal since it avoids a decoupling between the business domain and the infrastructure layer, however it requires a lot of DTO.
In short, note that the DDD approach is a free approach, since it is based on a set of good practices (TDD, BDD, CLEAN ARCHI and others). But does not define any specific architecture.
Personally I recommend using the one that will allow you to deliver your software faster
@@rolandjost3823
Fast Delivery in this way normally implies slowing maintenance in the future. I don't know if everything is valid just for Fast Delivery...
I agree with you @voult89, how would you structure your microservice ddd project? Can you provide some example. Just module, package names and so on.
If you have an interface which exposes save function and it is implemented in infrastructure layer, then the domain will never know how something is persisted or which is the underlying technology, this is exactly what was demonstrated here.
@@Boss-gr4jw Nope. He used annotation "Entity" and to use it as a JPA entity he made domain "Entity" mutable, created no arg constructor for JPA and so on. So, your domain module already knows what technology will be used.
data-JDBC, for example, doesn't need any of this staff.
Great talk, but still don't see any chance to use this in real world biz logic.
For example:
It do valid in domain object, but what if I got a new requirement that I need bypass or add some valid in some biz logic? It seems hard to do this new task.
Instead, with old school POJO way, it's easy.
The problem with keeping the data model with the domain model is a problem with java and spring. C# with dotnet solves the problem in an much elegant way. This makes C# a go to framework when thing about DDD. U should alway keep your domain model free from any infastructure concerns. Unfortunately spring jpa makes such aproach look like a boilerplate. Is this not a violation of the single responsibility principles?
Great talk
the repository call in the domain object is weird, just build a specification class and pass that instead.
Yeah, that's weird, especially when you need to create / update 10 000 entities...
Another year, another 'shiny concept'. Seems like this one is going to take us back to monoliths with the addition of confusion of what 'domain driven design' is. Seems like its someone else's turn in the spotlight to sell books and courses. I note hardly anyone talks about having a multi-module spring project e.g. multi-module Maven to decompose an application into. A lot less confusing than trying to introduce yet another concept/buzz-phrase/buzz-idea.
axon is the best ddd framework in java word
I feel like if I found a treasure
This might looks fancy but In my work experience, this way of modeling microservice is worst thing you can do in fast developing world. I want my developers to get features out as fast as possible with proper testing. I don't want them to waste time in managing packages.
controller, service, entities, repositories, util, helper. with No shitty one interface, one class thing.
just keep it simple !! You are not gonna need it.
One interface is good. You have a list of use cases in one place. I think they used to call it a facade :)
If needed, implementation can be split into classes
@@anton-tkachenko when needed your IDE can refactor out an interface in just 2 clicks. 🫠
That's how you end up with the anemic model and god classes which are impossible or hard to test. Also you end up putting functions together into services which are not related at all. This all results in so fragile code, hard to change, every change requires full recompilation of unrelated classes, slow builds, slow tests etc. There is a reason for why you should be designing into interfaces and smaller classes and packages. For very small service there is no reason not to put everything into same package, if it really is small.
I know many people love this approach because they never write a single test, so one big class works for them.
this approach intend isn't for simple projects or APIs (for that u can still use plain MVC), when a project grows and this involves scaling in complexity, let say after 1.5 year aprox, when more business rules are added if you don't have a Clean Architecture then u'll find out that the code is a mess and highly coupled, then making adaptations among business rules look really dirty in legacy approaches. Making code as faster as possible is the opposite of making high quality code (I prefer having code well organized and tested that can adapt in the future easily than writting fast code for a user story than will be broken in the near future)
Thank you very useful