Hey I find you to be an extremely effective teacher with a ton of very applicable knowledge and skills that I want to learn. Do you by chance have any longer form 'master classes' on different topics?
Looking forward to downloading the source code from Patreon and using it as a template/inspiration. I've been a developer for 10 years but still struggle daily to design simple and easy to read classes. These "back to basics" videos are still very much appreciated.
This channel appeals to long-time/part-time programmers as it offers a nice transition from the old TO the new ways and from the novice/average way TO the cool and clean way. Thank you, as always, Zoran!
9:42 Is there a good way to reduce complexity of sub dependencies intercommunication? I had the same clean class without logic, but later changes in one sub-system started to affect others. In the end my class have reimplementation of almos every public method of each dependency.
Great Video, thanks! Could you do a followup on how to make the book class serializable/deserializable? When having non primitive nested objects, serialization feels a lot harder.
@@g4schd I plan to do that at some point, but be aware that the model class will never be serializable/deserializable. That simply goes against its principal responsibilities.
Hi Zoran, thanks for the video. That's the approach I'm trying to aim. How can we deal with persisted model for this domain model? I'm not referring to GET endpoints where simple DTOs can be used. Let's consider PUT flow. Before changing the domain object it should be fetched from DB, so would you recommend to add the constructor with the only DTO that will instantiate the domain object bypassing all the checks for value objects?
There is another video on my channel where I am advocating the use of CQRS in complex models (ua-cam.com/video/tCpMD94HhB4/v-deo.html). That greatly simplifies a larger half of the problem, since it allows for several query models and one (large and complex) command model. The model in this video is essentially the command model. There would be no justification to invest so much into validation and consolidation of data just to support querying. Loading the command model from the database then depends on the technology used. In recent years, I have gradually come to favour aggregates. Relational databases are a tad difficult to work with when the model is organised around aggregates, but I am still using them on a daily basis successfully.
@@zoran-horvat thanks for the video, I've watched it 2 times 🙂 You mentioned that you used EF, so domain model is also a persistent one. Unfortunately, I don't have the power of EF and have 2 separate models: large complex domain(command) and POCO persistent model. Moreover, my read repo returns 3d DTO model which is almost identical to persistent one. There is a constructor of the domain model with DTO that initializes it bypassing all the validation checks. I'm just wondering whether it's an optimal solution, maybe there is a more elegant way how to initialize the domain model.
@@zoran-horvat What is your prefered method of mapping between domain and persistence models? Use persistence models to construct the domain model? And how about the other way around, once the domain model needs to be persisted, how to transform it into something serializable?
Thank you for this nice video. One question. How do we manage to put these objects in database. Let's say I want to put Book on a postgresql database. Do we create a table for each type here? Traditionally we were checking primitive types, validating and putting them as strings in database. Similar for reading too.
You can develop the database schema using everything you know about relational database design and still map these values easily. I don't like stringifying the data - it looks more like running away from the problem. There are a couple of recent videos on my channel where I have persisted this same object model into the database using EF Core. Each contained object had its own mapping into primitive types supported by the database, such as int, date, and varchar.
Genuinely asking, about IEdition why did you opt for an Interface? How do you suppose it will be used? Aren't you concerned that leaving the interface without methods will cause continuous Type Checking to use specific Getters\Methods? Marker Interface is considered bad isnt it? Thank you!
Marker interface is not considered bad, to begin with. It is a tool like any other in design. I have defined the interface because I needed a polymorphic type and had no other information about what that type would do. I only had a problem representing the state. Since no other requirements exist yet, there was no reason to define an abstract class, nor to define any members on the interface. But I am pretty sure the requirements will come in due time, which I would solve by defining members on the interface. That hint about IComparable was a good example of how the interface would attain methods later.
I began to dislike object-oriented-programming due to my experiences with it, but this channel is making me realise/remember how beautiful it can be when done right!
Fun fact: this style of writing software is not bound to OOP. You can define the exact same structure the professor wrote in Haskell using similar language constructs. The OOP you learned and grew to dislike is but the inheritance hell we were all taught was right for many years. But doing composition is so much better in most, if not all cases.
Ok watching this a second time now i understand why u choose an interface for the edition and an abstract record for the publicationDate. For the former you don't know all possible implementation so you use classic oop polymorphism, for the latter you use functional types since you know them all and they aren't likely to change any time soon. It's not like you didnt explain it clearly, but i've now put together in my mind all the points you made in other videos about the pros and cons of each approach.
@@ghevisartor6005 Thank you for your feedback! I am sure I could have done more to explain that point better. There will be more videos that include those two sets of types and I will remember your comment when I start talking about them again.
Thanks Zoran for another great video. One question regarding invoking static methods inside domain class. Shouldn't that be avoided because of testability in context of mocking? Or we can go with it when necessary and test it as "integrated" part of our model, which can in some cases be time consuming to prepare relevant test data? In Java a saw a solution with replacing static class with interface with default methods which can be easily mocked.
If you are referring to extension methods on the List class, those are what I just said: methods on the List class. You should not view them as external dependencies. On the other hand, when it comes to testing those methods in isolation, you will notice that those are stateless functions. That makes them highly testable.
EF cannot track immutable classes, so you either pass it the modified object to detect changes or not use EF for persistence. If the model is entirely or dominantly immutable, then IQueryable remains the only benefit and the downsides become too great to continue using it.
I might be rushing ahead and am currently feeling stupid. The Design is clean and can easily be used in code for creating new books. But how would i now deserialize such a book either from database or json. Which IEdition or PublicationDate implementation should be used? I mean i can create a custom serializer but then this one needs to be bound to all the possible implementations, and also be cumbersome to create. So i would basically trade Book surface design against Serialization logic.
Serialization and deserialization do not belong to the model, especially if it encapsulates its state. JSON serialization/deserialization should be based on DTOs that support the schema. Database persistence depends on the technology used.
@@zoran-horvatif you work with blazor wasm would you reuse these classes if you had for example to make it possible in the Ui to swap order of author?
@@zoran-horvat ah i ment like you build these objects from the db, then map them to dtos, send to client, the client map them back again to the same objects and show them in the Ui
@@zoran-horvat I see, but the dtos/mapper would then need to have some logic and binding in place of how to determine which actual IEdition to create. Or would I there probably use something like an property $Type to store the implementing class with the data?
Hello, Mr. Hovart. You are using VS code , high likely with C# extensions provided by Microsoft. This developing environment is enough for learning C#. However, the C# extensions has the same license policy as VS 2022 community does, which means it is allowed for open source, Microsoft tools or education but not for cases like $1M turnover, 250 employees, or the bigger organizations . The problem is that, unlike VS, C# extensions doesn't provide any paid version, which means Microsoft prohibits it from being used as a professional tool. It seems that they want those learners to grow as payers for VS so decided to kill Omnisharp by introducing the extension. I would like to hear your opinion about it.
Actually, I don't have an opinion on that question. Since I work on R&D projects only, and abandon them as soon as they become sustainable, I never had to consider the licenses. Now that you asked, I see how blessed I am, in fact.
I mentioned before and I say again, I love the way you code. It makes stuff so simple. But its really really really hard for me even though it looks simple to do. Do you have a course teaching this? Edit: Pluralsight and Udemy
There is one course at Udemy explaining the basics. Another course explaining OOP in greater depth is coming up (it is in preview at my Patreon page). And yet another course specifically about OOD might come later.
I have always seen arguments for "never use getters and setters". It is understandable to not use "setters" in command model. However I do not see any argument for not using getters. I want to load a model, validate it, apply behaviours, and then persist. For this getters are necessary for serialization. Any opinion on how to use "getters" the right way?
@@zoran-horvat Setters makes sense in DTOs, but in domain model, setters doesn't express the behaviour the client has intended to apply. A behaviour may involve modifying one or more than one properties of the model. Behaviours also gives opportunity for capturing domain events
because when you introduce more classes, you essentially introduce more GC calls, which can impact the runtime. so, how do they compare ? using primitives vs complex types
@@noctavel Yes, but you introduce all that on top of I/O, including database and network access, which take three orders of magnitude more time than the CPU-bound part of the operation. The fear of GC is almost invariably irrational.
Genuine question: Do you really believe in classes having a universally valid state and trying to enforce it? Why is validity not context dependent? For instance, a Book with a null publisher might be valid for review but not valid for publication. That is, a book with a null publisher might be valid in one context but invalid in another. Thanks a lot for the video. I genuinely appreciate it! 😊
@@steff.h Validity doesn't have to belong to the class, so I agree with you if that is what you are aiming at. In complex domains, the class usually tests "physical" correctness, so to say, like ensuring that objects exist. Full validity is often subject to knowing other rules, just as you pointed out, and in that case we usually rely on a factory to instantiate the class according to dynamic rules. In designs of that kind, it is often beneficial to also install a fitness function that asserts that nobody but concrete factories invoke the class's constructor.
Hey I find you to be an extremely effective teacher with a ton of very applicable knowledge and skills that I want to learn. Do you by chance have any longer form 'master classes' on different topics?
Only the courses at Pluralsight and Udemy. There are links in this video's description.
@@zoran-horvat I have done Udemy courses and I highly recommend them!
@@chrisspire And I have completed Zoran's courses in Pluralsight and highly recommend those as well.
You all thought Zoran was just a programmer, but his videos are about mastering the art of Zen.
I'm still mastering the art of when.
This video is pure gold worth watching over and over, it covers the most fundamental of OOP. Thank you, Zoran.
I love the statement "Law of Customer Engagement" and I feel it every day! :)
The intonation you speak reminds me of old knights and dragons stories narrated by a wise magician. OOP magician.
That was intentional :)
Looking forward to downloading the source code from Patreon and using it as a template/inspiration. I've been a developer for 10 years but still struggle daily to design simple and easy to read classes. These "back to basics" videos are still very much appreciated.
The source code is now available on Patreon. Sorry you had to wait.
This video is absolute gold for people already familiar with oop. Love it, thank you.
This channel appeals to long-time/part-time programmers as it offers a nice transition from the old TO the new ways and from the novice/average way TO the cool and clean way. Thank you, as always, Zoran!
9:42 Is there a good way to reduce complexity of sub dependencies intercommunication? I had the same clean class without logic, but later changes in one sub-system started to affect others. In the end my class have reimplementation of almos every public method of each dependency.
P.S. I found an answer (in the form of no solution) in one of your last shorts.
Hah I really like these little sarcasm grains here and there.
Your videos are nicely direct, no clutter. New sub!
Great Video, thanks! Could you do a followup on how to make the book class serializable/deserializable? When having non primitive nested objects, serialization feels a lot harder.
@@g4schd I plan to do that at some point, but be aware that the model class will never be serializable/deserializable. That simply goes against its principal responsibilities.
Now this is a video worth becoming a Patreon for. There's so much gold here and I want it :-)
After watching a few of his other gem videos, I also joined the Patreon.
Thanks, good content as always :). Btw at 11:42 I think you forgot to make FullDate, YearMonth, Year inherit PublicationDate record
Thanks for noting. It was a silly mistake.
@@zoran-horvat From a legend like you, Microsoft is probably making it a feature in upcoming C# version :D
3:23 Object Oriented Programmers keep walking brainlessly through that mud. 😂😂😂
That thought was hanging in the air in at least 50 of my previous videos :)
And now it's out!
@@zoran-horvat Well, now you saved me from walking through that mud. 😊👍🏼
This is a story, a poetry. You are the Shakespeare of programming :)
Not a single inheritance used, nice! (I don't count "records one-level-hierarchy as an C# union implementation" for obvious reasons)
It is object composition all the way down.
Hi Zoran, thanks for the video. That's the approach I'm trying to aim. How can we deal with persisted model for this domain model? I'm not referring to GET endpoints where simple DTOs can be used. Let's consider PUT flow. Before changing the domain object it should be fetched from DB, so would you recommend to add the constructor with the only DTO that will instantiate the domain object bypassing all the checks for value objects?
There is another video on my channel where I am advocating the use of CQRS in complex models (ua-cam.com/video/tCpMD94HhB4/v-deo.html). That greatly simplifies a larger half of the problem, since it allows for several query models and one (large and complex) command model.
The model in this video is essentially the command model. There would be no justification to invest so much into validation and consolidation of data just to support querying. Loading the command model from the database then depends on the technology used. In recent years, I have gradually come to favour aggregates. Relational databases are a tad difficult to work with when the model is organised around aggregates, but I am still using them on a daily basis successfully.
@@zoran-horvat thanks for the video, I've watched it 2 times 🙂 You mentioned that you used EF, so domain model is also a persistent one. Unfortunately, I don't have the power of EF and have 2 separate models: large complex domain(command) and POCO persistent model. Moreover, my read repo returns 3d DTO model which is almost identical to persistent one. There is a constructor of the domain model with DTO that initializes it bypassing all the validation checks. I'm just wondering whether it's an optimal solution, maybe there is a more elegant way how to initialize the domain model.
@@zoran-horvat What is your prefered method of mapping between domain and persistence models? Use persistence models to construct the domain model? And how about the other way around, once the domain model needs to be persisted, how to transform it into something serializable?
Very insightful video! Would be happy to hear how you would use this approach with ef core 🤓
Thank you for this nice video.
One question. How do we manage to put these objects in database. Let's say I want to put Book on a postgresql database. Do we create a table for each type here? Traditionally we were checking primitive types, validating and putting them as strings in database. Similar for reading too.
You can develop the database schema using everything you know about relational database design and still map these values easily. I don't like stringifying the data - it looks more like running away from the problem.
There are a couple of recent videos on my channel where I have persisted this same object model into the database using EF Core. Each contained object had its own mapping into primitive types supported by the database, such as int, date, and varchar.
Genuinely asking,
about IEdition why did you opt for an Interface?
How do you suppose it will be used?
Aren't you concerned that leaving the interface without methods will cause continuous Type Checking to use specific Getters\Methods? Marker Interface is considered bad isnt it? Thank you!
Marker interface is not considered bad, to begin with. It is a tool like any other in design.
I have defined the interface because I needed a polymorphic type and had no other information about what that type would do. I only had a problem representing the state. Since no other requirements exist yet, there was no reason to define an abstract class, nor to define any members on the interface.
But I am pretty sure the requirements will come in due time, which I would solve by defining members on the interface. That hint about IComparable was a good example of how the interface would attain methods later.
I began to dislike object-oriented-programming due to my experiences with it, but this channel is making me realise/remember how beautiful it can be when done right!
Fun fact: this style of writing software is not bound to OOP. You can define the exact same structure the professor wrote in Haskell using similar language constructs. The OOP you learned and grew to dislike is but the inheritance hell we were all taught was right for many years. But doing composition is so much better in most, if not all cases.
Don't we need to derive from the PublicationDate (in the last seconds)?
Yes, that is what I meant to do. Sorry for the mistake.
Is it possible in ef core to map the book class (with the authors list in the constructor)? Or can anyone point me in the right direction?
I’d be interested in this too.
On this point, if you work with ef, you still use this book class, it's not like you make another layer, separating Book and BookEntity, right?
There are a few earlier videos on the bookstore application example where I persisted all using EF Core. It wasn't hard at all.
This is all above my level but I watch it anyway.
The customer laws catches me 😂
Ok watching this a second time now i understand why u choose an interface for the edition and an abstract record for the publicationDate.
For the former you don't know all possible implementation so you use classic oop polymorphism, for the latter you use functional types since you know them all and they aren't likely to change any time soon.
It's not like you didnt explain it clearly, but i've now put together in my mind all the points you made in other videos about the pros and cons of each approach.
@@ghevisartor6005 Thank you for your feedback! I am sure I could have done more to explain that point better.
There will be more videos that include those two sets of types and I will remember your comment when I start talking about them again.
Thanks Zoran for another great video. One question regarding invoking static methods inside domain class. Shouldn't that be avoided because of testability in context of mocking? Or we can go with it when necessary and test it as "integrated" part of our model, which can in some cases be time consuming to prepare relevant test data? In Java a saw a solution with replacing static class with interface with default methods which can be easily mocked.
If you are referring to extension methods on the List class, those are what I just said: methods on the List class. You should not view them as external dependencies.
On the other hand, when it comes to testing those methods in isolation, you will notice that those are stateless functions. That makes them highly testable.
Hi Zoran. Thank for a great video!
How do you persist an abstract record like PublicationDate with EF?
EF cannot track immutable classes, so you either pass it the modified object to detect changes or not use EF for persistence. If the model is entirely or dominantly immutable, then IQueryable remains the only benefit and the downsides become too great to continue using it.
@@zoran-horvat What tool do you use for persistence when you work with immutable classes?
@@AndersBaumann I usually go with Dapper.
@@zoran-horvat OK. Maybe a future video to show how you would persist the classes in this video with Dapper?
@@AndersBaumann I have plans about that, but no time frame right now.
Thank you teacher
I might be rushing ahead and am currently feeling stupid. The Design is clean and can easily be used in code for creating new books. But how would i now deserialize such a book either from database or json. Which IEdition or PublicationDate implementation should be used? I mean i can create a custom serializer but then this one needs to be bound to all the possible implementations, and also be cumbersome to create. So i would basically trade Book surface design against Serialization logic.
Serialization and deserialization do not belong to the model, especially if it encapsulates its state. JSON serialization/deserialization should be based on DTOs that support the schema. Database persistence depends on the technology used.
@@zoran-horvatif you work with blazor wasm would you reuse these classes if you had for example to make it possible in the Ui to swap order of author?
@@ghevisartor6005 This object model is compatible with WASM.
@@zoran-horvat ah i ment like you build these objects from the db, then map them to dtos, send to client, the client map them back again to the same objects and show them in the Ui
@@zoran-horvat I see, but the dtos/mapper would then need to have some logic and binding in place of how to determine which actual IEdition to create. Or would I there probably use something like an property $Type to store the implementing class with the data?
Hello, Mr. Hovart.
You are using VS code , high likely with C# extensions provided by Microsoft.
This developing environment is enough for learning C#.
However, the C# extensions has the same license policy as VS 2022 community does, which means it is allowed for open source, Microsoft tools or education but not for cases like $1M turnover, 250 employees, or the bigger organizations .
The problem is that, unlike VS, C# extensions doesn't provide any paid version, which means Microsoft prohibits it from being used as a professional tool.
It seems that they want those learners to grow as payers for VS so decided to kill Omnisharp by introducing the extension.
I would like to hear your opinion about it.
Actually, I don't have an opinion on that question. Since I work on R&D projects only, and abandon them as soon as they become sustainable, I never had to consider the licenses. Now that you asked, I see how blessed I am, in fact.
I mentioned before and I say again, I love the way you code. It makes stuff so simple. But its really really really hard for me even though it looks simple to do. Do you have a course teaching this?
Edit: Pluralsight and Udemy
There is one course at Udemy explaining the basics. Another course explaining OOP in greater depth is coming up (it is in preview at my Patreon page). And yet another course specifically about OOD might come later.
I have always seen arguments for "never use getters and setters". It is understandable to not use "setters" in command model. However I do not see any argument for not using getters.
I want to load a model, validate it, apply behaviours, and then persist. For this getters are necessary for serialization.
Any opinion on how to use "getters" the right way?
What are the arguments to "never use setters"? How is it understandable to not use setters in a command model?
@@zoran-horvat Setters makes sense in DTOs, but in domain model, setters doesn't express the behaviour the client has intended to apply.
A behaviour may involve modifying one or more than one properties of the model.
Behaviours also gives opportunity for capturing domain events
@@SwarupMahapatra-e9v What is the difference between x.Something = y; and x.SetSomething(y);?
same thing. It doesn't encapsulate any behaviour
@@swarupmahapatra1 What behavior? The command is to set something to y, as per the requirements.
Loved it. 👏👏👏 More of these type of videos please.
Hi, do you have any Udemy course that teaches these kind of advanced concepts… I would love to buy that course
I plan to make one in the future.
True Masterpiece. Why not a million subscribers for this channel 😢
how about performance in this context?
@@noctavel Performance of what?
because when you introduce more classes, you essentially introduce more GC calls, which can impact the runtime. so, how do they compare ? using primitives vs complex types
@@noctavel Yes, but you introduce all that on top of I/O, including database and network access, which take three orders of magnitude more time than the CPU-bound part of the operation. The fear of GC is almost invariably irrational.
Genuine question: Do you really believe in classes having a universally valid state and trying to enforce it? Why is validity not context dependent? For instance, a Book with a null publisher might be valid for review but not valid for publication. That is, a book with a null publisher might be valid in one context but invalid in another.
Thanks a lot for the video. I genuinely appreciate it! 😊
@@steff.h Validity doesn't have to belong to the class, so I agree with you if that is what you are aiming at. In complex domains, the class usually tests "physical" correctness, so to say, like ensuring that objects exist. Full validity is often subject to knowing other rules, just as you pointed out, and in that case we usually rely on a factory to instantiate the class according to dynamic rules. In designs of that kind, it is often beneficial to also install a fitness function that asserts that nobody but concrete factories invoke the class's constructor.
was hoping for a videos on delegates but always appreciate your uploads!
Man, after the first 4 minutes, I feel so triggered I need to step away from the computer.
Is that good? :)
@@zoran-horvat everything you've posted is good, so yes! In this case, it just makes the following 6 minutes that much more satisfying. :)
⚪👌👌👌👌👌👌👌👌
👌😎