@@zoran-horvat What about Dapper, do you have any example of using domain models with Dapper? Thanks for sharing your knowledge, you are an excellent teacher!
@@guillermomazzari8320 Using Dapper goes a bit easier and more directly than EF Core. That is why I do not show it in the videos. Another reason is that it can sometimes get in the way when discussing some modeling concepts. I do have a few ideas about Dapper, though, and I might come up with a video that showcases it in the future.
Viewers might see any of your videos as their first. It may be helpful to link related videos in the description. For example, a video of fixing an anemic domain model would be a useful item to link in this video. One can, of course, search through the channel, but you now have over 100 videos.
@@CharlesBurnsPrime Currently there exists no such ordering in my channel. I count on the TH-cam algorithm to suggest next videos that are most suitable to each viewer. Some TH-camrs have reported that that worked better than what they did manually!
@@zoran-horvatthis video is my first one and I didn't get any useful suggestions from TH-cam, so it just looks like a waste of time to see a problem without its solution
@@MohamedESSANOUSY There are many solutions, not just one. More than a hundred videos on my channel teach how to construct them in an object-oriented and functional style, one step at a time. If you wanted "a solution" in one video, then sorry. There is no such thing.
@@modernkennnern But the story of JSON is simple: it is the public contract, so you decide what it will be. In this demo, I have encoded the PartialDate as a string representing the date, potentially with some parts missing. For example, "2023", "2023-05", and "2023-05-17" are three valid values for the partial date field in JSON, which I would convert to a polymorphic type on reception.
@@zoran-horvat I assume this mapping is not defined in the domain model itself (`PartialDate` in this context), but rather in some intermediate layer; this is where I'm currently confused. What is this layer? Should the outermost layer be stringly typed? With so many external requirements the dto layer becomes so complicated; a value object not only requires you to define a custom json converter but also a separate OpenAPI descriptor. It also possibly requires a custom TryParse in case of form-data and probably other things I can't think of off the top of my head. Stringly typed dtos removes all of these issues, but they make validation complicated 😭, and as the saying goes "Parse. Don't validate". I've been programming professionally for almost 4 years now but I've only recently been able to create my first greenfield project and as you might understood this presentation layer is where most of my architectural issues lie 😞
@modernkennnern Any mapping to and from JSON belongs to the entity that owns it - an endpoint in the minimal API application, for example. Once the data enter that entity, they must be objects. JSON is only for communication and transfer.
For example, I have a service. A client can query it, then the service itself queries another service via grpc, then it queries redis, makes some data processing, maps the response and returns it to the client. It is very clear how it can be done using anemic models. But what about OOP-style? How will it look like?
@@ShowoffFantasy How about not just querying? Wasn't my point that there are no significant issues while CRD is all that you need? Now to answer your question, it is common to apply CQRS to any complex system. It is just easier to operate with numerous distinct query models and only one complex command model. The domain model plays no role in querying. Think for yourself: what would the domain model do in a query?
Anemic model definitions seem like simple data type and layout definition. Just types the data in a way that language used understands (C#, Java, F#, Scala etc. etc.) and nothing else (lacks behavior). Like a data contract only. Makes no sense in languages such as C# unless unavoidable (i.e using libraries and frameworks with none or basic mapping capabilities). Then it would still be possible to create and use rich domain model with custom in-house mapping (which can be problematic to maintain).
I was on board with the idea entire time until 11:07, where you suggested to expose "one update operation" for the entire Book model on the Service. This, on my opinion, belongs to the Repository, that only cares about persistence and not business rules. The service should orchestrate calls to the book entity methods based on the use-case. By exposing a single update method on the Service, you remove all meaning from the operation - the consumer of the API rarely wants to update everything about the entity. Often, there are rules that prevent updating two pieces of data at once in the same transaction, because those operations may have different business implication (and trigger mutually exclusive actions). It is also possible that I'm being overly pedantic and what you're showing here as a Service, is what I call a Repository, and all is well in the end.
@@PapoochCZ If you use a service layer, then the operation naturally belongs there. For example, you will pass a detached entity to the service, which manages it further. On the other hand, the service would use the repository, as it does in my example. Please remember that in many applications, such as Web APIs, there won't be any service layer - the API itself is the service.
@@krccmsitp2884 Yes, that is one of the points, which I could not cover in this video. All concerns are off in the rich domain model. In that case, every instance of a Book must have already passed the domain rules check.
In this world the 'service' work is often in the domain model. By the time it gets to persisting, its already in a valid state with those invariants handled and you can't muck it up. There will be a 1:M between those domain objects and this update method instead of 1:N between structs and service methods you're probably used to.
@@yanivrubin7202 It is not true that functional models have no polymorphism. Discriminated unions are a critical part of functional modeling, and they are as polymorphic as classes with one level of inheritance in an object-oriented model. Functional modeling is also heavily using object composition alongside function composition. A custom type will typically consist of other custom types, rather than primitive types only.
I think you will want to be careful about 'polymorphism' as there is state vs behavior. For example, implementing an interface is polymorphism but not the nasty/brittle OOP state inheritance kind. Theres a bit of conflation between modeling and types. While FP does not couple the data and the processing like OOP, that doesn't mean its all primitives either. You can have a function that takes 'rich' types as arguments
@@zoran-horvat When you map entity types to model types, there is nothing stopping you from using more complex types and doing proper object composition when it makes sense
Learn more at Brilliant brilliant.org/ZoranHorvat/
This link gives you a 30-day free trial and 20% off of an annual premium subscription.
“This service could have been an endpoint” has big “this meeting could have been an email” energy.
@@RickGladwin True. With a proper domain model and EF Core I would never bother to create the services layer.
@@zoran-horvat What about Dapper, do you have any example of using domain models with Dapper? Thanks for sharing your knowledge, you are an excellent teacher!
@@guillermomazzari8320 Using Dapper goes a bit easier and more directly than EF Core. That is why I do not show it in the videos. Another reason is that it can sometimes get in the way when discussing some modeling concepts. I do have a few ideas about Dapper, though, and I might come up with a video that showcases it in the future.
@@zoran-horvat Thanks for taking the time to answer
Thank you for publishing an interesting video. Waiting for the second part with the "rich domain" explanation.
Viewers might see any of your videos as their first. It may be helpful to link related videos in the description. For example, a video of fixing an anemic domain model would be a useful item to link in this video.
One can, of course, search through the channel, but you now have over 100 videos.
@@CharlesBurnsPrime Currently there exists no such ordering in my channel. I count on the TH-cam algorithm to suggest next videos that are most suitable to each viewer. Some TH-camrs have reported that that worked better than what they did manually!
@@zoran-horvatthis video is my first one and I didn't get any useful suggestions from TH-cam, so it just looks like a waste of time to see a problem without its solution
@@MohamedESSANOUSY There are many solutions, not just one. More than a hundred videos on my channel teach how to construct them in an object-oriented and functional style, one step at a time. If you wanted "a solution" in one video, then sorry. There is no such thing.
3:55 - Martin Fowler
4:20 - Service
What is the video that you turn this to a rich domain? Did you do it yet or in the future?
@@vuhoang5903 It's in the future at this moment.
How would you design a dto model? How would I map it from the domain model? How would I go about json serialization a polymorphic Edition?
@@modernkennnern That is the next video. Next week.
@zoran-horvat Can't wait! 🍻
@@modernkennnern But the story of JSON is simple: it is the public contract, so you decide what it will be. In this demo, I have encoded the PartialDate as a string representing the date, potentially with some parts missing. For example, "2023", "2023-05", and "2023-05-17" are three valid values for the partial date field in JSON, which I would convert to a polymorphic type on reception.
@@zoran-horvat I assume this mapping is not defined in the domain model itself (`PartialDate` in this context), but rather in some intermediate layer; this is where I'm currently confused. What is this layer? Should the outermost layer be stringly typed?
With so many external requirements the dto layer becomes so complicated; a value object not only requires you to define a custom json converter but also a separate OpenAPI descriptor. It also possibly requires a custom TryParse in case of form-data and probably other things I can't think of off the top of my head. Stringly typed dtos removes all of these issues, but they make validation complicated 😭, and as the saying goes "Parse. Don't validate".
I've been programming professionally for almost 4 years now but I've only recently been able to create my first greenfield project and as you might understood this presentation layer is where most of my architectural issues lie 😞
@modernkennnern Any mapping to and from JSON belongs to the entity that owns it - an endpoint in the minimal API application, for example. Once the data enter that entity, they must be objects. JSON is only for communication and transfer.
Thank you for your videos! They are extremely helpful and the quality is on another level. I'm looking forward to the next video on this topic 👍🏻👍🏻
For example, I have a service. A client can query it, then the service itself queries another service via grpc, then it queries redis, makes some data processing, maps the response and returns it to the client.
It is very clear how it can be done using anemic models. But what about OOP-style? How will it look like?
@@ShowoffFantasy How about not just querying? Wasn't my point that there are no significant issues while CRD is all that you need?
Now to answer your question, it is common to apply CQRS to any complex system. It is just easier to operate with numerous distinct query models and only one complex command model. The domain model plays no role in querying. Think for yourself: what would the domain model do in a query?
Anemic model definitions seem like simple data type and layout definition. Just types the data in a way that language used understands (C#, Java, F#, Scala etc. etc.) and nothing else (lacks behavior). Like a data contract only.
Makes no sense in languages such as C# unless unavoidable (i.e using libraries and frameworks with none or basic mapping capabilities). Then it would still be possible to create and use rich domain model with custom in-house mapping (which can be problematic to maintain).
I was on board with the idea entire time until 11:07, where you suggested to expose "one update operation" for the entire Book model on the Service. This, on my opinion, belongs to the Repository, that only cares about persistence and not business rules.
The service should orchestrate calls to the book entity methods based on the use-case. By exposing a single update method on the Service, you remove all meaning from the operation - the consumer of the API rarely wants to update everything about the entity. Often, there are rules that prevent updating two pieces of data at once in the same transaction, because those operations may have different business implication (and trigger mutually exclusive actions).
It is also possible that I'm being overly pedantic and what you're showing here as a Service, is what I call a Repository, and all is well in the end.
@@PapoochCZ If you use a service layer, then the operation naturally belongs there. For example, you will pass a detached entity to the service, which manages it further.
On the other hand, the service would use the repository, as it does in my example.
Please remember that in many applications, such as Web APIs, there won't be any service layer - the API itself is the service.
Consider the book being an Aggregate in the sense of DDD.
@@krccmsitp2884 Yes, that is one of the points, which I could not cover in this video. All concerns are off in the rich domain model. In that case, every instance of a Book must have already passed the domain rules check.
In this world the 'service' work is often in the domain model. By the time it gets to persisting, its already in a valid state with those invariants handled and you can't muck it up.
There will be a 1:M between those domain objects and this update method instead of 1:N between structs and service methods you're probably used to.
Does't the anemic donation model shares some similarities to functional programming? Mainly the lack of polymorphism?
@@yanivrubin7202 It is not true that functional models have no polymorphism. Discriminated unions are a critical part of functional modeling, and they are as polymorphic as classes with one level of inheritance in an object-oriented model.
Functional modeling is also heavily using object composition alongside function composition. A custom type will typically consist of other custom types, rather than primitive types only.
I think you will want to be careful about 'polymorphism' as there is state vs behavior. For example, implementing an interface is polymorphism but not the nasty/brittle OOP state inheritance kind.
Theres a bit of conflation between modeling and types. While FP does not couple the data and the processing like OOP, that doesn't mean its all primitives either. You can have a function that takes 'rich' types as arguments
@@zoran-horvat When you map entity types to model types, there is nothing stopping you from using more complex types and doing proper object composition when it makes sense
@@Mike-uk2oq That is what my previous videos are demonstrating on this same object model.
Can't do my homework when my head hurts
The best word for your videos: seductive. You are dangerous.
I think it’s the deep Eastern European accent… and the fact that you are never in a rush to speak.
We want a video about clean architecture
@@MahmoudSaed98 Beware of what you wish for.
When do we want it? 😂