Тёмный

How To Use Domain-Driven Design In Clean Architecture 

Milan Jovanović
Подписаться 90 тыс.
Просмотров 102 тыс.
50% 1

Get the source code for this video for FREE → the-dotnet-weekly.ck.page/ric...
☄️ Master the Modular Monolith Architecture: bit.ly/3SXlzSt
📌 Accelerate your Clean Architecture skills: bit.ly/3PupkOJ
🚀 Support me on Patreon to access the source code: / milanjovanovic
Clean architecture is a good choice when you want to design a robust and flexible application. The core of the Clean Architecture is the Domain layer. This is where you should define your important domain (or business) rules. In this video, I will show you how to go from an Anemic Domain model to a Rich Domain model by moving the application logic into the Domain layer. We will apply some of the concepts from Domain-Driven Design.
Join my weekly .NET newsletter:
www.milanjovanovic.tech
Subscribe for more:
ru-vid.com...
Chapters
0:00 What we are going to build
1:23 Anemic domain model
2:54 Refactoring to a rich domain model - Part 1
4:33 Static factory pattern
8:16 Refactoring to a rich domain model - Part 2
11:21 How to encapsulate collections
16:35 Refactoring to a rich domain model - Part 3
18:32 Moving logic to the domain layer
21:49 How to encapsulate collections (again)
24:15 How to deal with external dependencies
28:12 Questions left unanswered
29:58 How to get the source code

Наука

Опубликовано:

 

29 июн 2024

Поделиться:

Ссылка:

Скачать:

Готовим ссылку...

Добавить в:

Мой плейлист
Посмотреть позже
Комментарии : 282   
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Master the Clean Architecture: bit.ly/3PupkOJ
@JOHNSONLOBOlobojony
@JOHNSONLOBOlobojony Год назад
I registered today. How can I get previous new letters? Can you help me
@MilanJovanovicTech
@MilanJovanovicTech Год назад
@@JOHNSONLOBOlobojony Send me an email at milan@milanjovanovic.tech!
@newraze
@newraze Год назад
Honestly. After few weeks of learning fundamentals of DDD, watching conferences, tutorials, reading blogs and articles about how and what to refactor, why this or that way, when and what set to private/internal or leave public I can say with 100% sure - this is the best explained video concerning this topic. Now its going to be easier for me to refactor my learning projects from anemic to rich model and be motivated to write code again :)
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Hi Mateusz, I am blown away by your feedback. I had to read it a few times out of joy. Your comment makes all my effort in producing these videos worthwhile!
@Flanno91
@Flanno91 Год назад
@@MilanJovanovicTech I have to agree with Mateusz. I am currently working on a solo project that I would like to rewrite using DDD and watching your videos as well as Amichai Mantinband's are helping me understand the whole architecture model so well. The best thing is how current this all is because .NET has undergone so many changes in the past few years. A lot of the videos I had been using to learn DDD with .NET are just out of date once it gets to the deeper .NET development. Please please keep it up.
@odoolabs1366
@odoolabs1366 Год назад
Mateusz ! I am starting DDD training can you please guide me what should be my roadmap so that I dont waste time going here and there please ?
@EmptyGlass99
@EmptyGlass99 Год назад
You have a gift for comprehensive and precise communication without unnecessary filler material.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
I never thought of it as a gift, but thank you very much 😊
@timurrozhok2685
@timurrozhok2685 8 месяцев назад
I really like how you explain complex concepts and designs in a such simple way. Extra butter to your videos is that examples are not "dead" - you try showing things on cases that are close to real domains. No "Foo" and "Bar" involved, which is really great!
@MilanJovanovicTech
@MilanJovanovicTech 8 месяцев назад
I've got some awesome DDD videos coming out in about a week 😁
@timurrozhok2685
@timurrozhok2685 8 месяцев назад
@@MilanJovanovicTech I'm looking forward to it 🤩
@tiagocandeias3969
@tiagocandeias3969 Год назад
Milan, needless to say that this was once again a great and awesome video :) Great work picking a somehow complex topic and make it look like a simple action without being lost at the definition hell of DDD :)
@MilanJovanovicTech
@MilanJovanovicTech Год назад
People learn better by watching/doing then they do by reading. So I had to get creative and think of something practical. Really appreciate the support Tiago!
@user-lo9ih5wd1l
@user-lo9ih5wd1l 3 месяца назад
Honestly, this is the first video that I fully understand from this channel. I know that the owner of the channel is a high-level person, but the videos he shows are always short. It shows the problem quickly, but in this video I got a very high benefit. I hope the channel owner makes videos like this in the future . in end thanks Milan 😎🎯👨‍💻
@MilanJovanovicTech
@MilanJovanovicTech 3 месяца назад
Noted!
@sushilb7994
@sushilb7994 Год назад
Milan, another great and useful video! I must say you choose video topics wisely and bringing quality content. Would love to see more on domain driven design concepts with the examples.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Thank you very much Sushil. Make sure you watch the new video about Entities to wrap up this topic 😁
@gbbigardi
@gbbigardi Год назад
A friend of mine recommended your channel and your videos are awesome! Keep up with the good work man!!
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Thank you for watching, Gustavo, I'm glad you liked it! And also thank your friend for me, for recommending my channel 😁
@junior.santana
@junior.santana Год назад
Awesome! I really liked the fact that you didn't just bring a finished solution and showed it, but rather explained the process step-by-step and the reasonings for each decision. That's a clever way of teaching this topic. I'll try to binge-watch your videos about DDD as this is a new subject for me.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
I have a recent playlist where I started modeling a domain from scratch, worth checking out
@krccmsitp2884
@krccmsitp2884 Год назад
I liked your step-by-step approach and your explanations about postponed decisions.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Thanks a lot!
@natalijagajic4114
@natalijagajic4114 Год назад
Really nice topic and great content! As someone working in education, I appreciate your effort to give such nice practical examples.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Thank you Natalija, feedback like yours really motivates me to keep going 😊
@rafapioli75
@rafapioli75 Год назад
Great explanation! Thanks for your efforts to create this kind of content! I learned a lot from this video.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
That's excellent. My hope is you will continue to find value in the future videos
@branislavpetrovic7486
@branislavpetrovic7486 Год назад
Great video with proper duration for the topic! Excellent example of transforming anemic to rich domain model. Thanks!
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Thank you so much Branislav. What is your biggest takeaway from this video?
@branislavpetrovic7486
@branislavpetrovic7486 Год назад
@@MilanJovanovicTech It is cleaning handlers from business logic to follow SRP and moving responsibility to gathering domain model for nested properties business logic.
@JOHNSONLOBOlobojony
@JOHNSONLOBOlobojony Год назад
Thank you very much Milan. started getting good exposure into clean architecture and DDD. good luck!
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Awesome, I'm sure you are going to enjoy it 😁
@paulbarton2280
@paulbarton2280 Год назад
Great content, keep it up. I would like to see a video on separating your domain via bounded contexts and how that would work with EF.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
That's a great topic, but I want to cover some basics first before tackling that. And I also need a more complex domain for the explanation to make sense. I will think about it, maybe I can re-work this idea to fit the bill.
@newguycho
@newguycho Год назад
Great video thanks! Can't wait for the next one to see how you gonna handle unanswered question with sending the email. As you told me on previous video probably it's going to be with mediatr publish notification. Keep up the great work!
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Exactly, I want to show a solution using Domain Events, MediatR INotification and the Outbox pattern. Will make for quite a video 😁
@ajaysingh-sc1qt
@ajaysingh-sc1qt Месяц назад
Lucky I came across this video...... and finally got understanding what we were doing wrong. Thanks for the excellent content.
@MilanJovanovicTech
@MilanJovanovicTech Месяц назад
What was the issue you were seeing?
@ajaysingh-sc1qt
@ajaysingh-sc1qt Месяц назад
@@MilanJovanovicTech kept business logics were in handler or business classes. and Entities with only properties.
@fadygamilmahrousmasoud5863
@fadygamilmahrousmasoud5863 Год назад
i think this is the best explanation so far about how to design a rich domain, Thank you Milan. And i am really waiting for a series in which you start building a project from scratch to see the best practices of design and layers implementation with you, Thank you again for your efforts❤
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Thank you so much! Be sure to check out some of my other videos :)
@fadygamilmahrousmasoud5863
@fadygamilmahrousmasoud5863 Год назад
@@MilanJovanovicTech Hello again Milan 😀 I just watched this video multiple times to get more details, but i need to ask you a question because i am working on a personal project now and i decided to go with the clean arch. to practice on it, As i know the idea form this arch is to stop thinking about the data-centric approach and start thinking about the business-rules and behaviour, okay that's great but when i started to design my rules to implement the domain i found myself thinking about the design of the entities and the relationships btn them and FK and this stuff .. so i am right or not because as i understand from this video you already know the relations btn the entities before refactoring ??
@laptoprecaia.k.aagentsmith3328
I am amazed. Thank you Milan.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
You're welcome :)
@zawette
@zawette Год назад
Very well put video !
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Thank you!
@VladyslavHorbachov
@VladyslavHorbachov Год назад
Great job, bro👍👍 Waiting for the next videos
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Thanks!
@mehranlabour
@mehranlabour 9 месяцев назад
Thanks Milan, You are perfect as always
@MilanJovanovicTech
@MilanJovanovicTech 9 месяцев назад
Thanks, you too! :)
@dhanushshetty7840
@dhanushshetty7840 Год назад
Found you on LinkedIn. Love design related videos you're posting!!
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Thank you very much. I'm glad you like my content so far, I'm trying to improve and get better with every video.
@wvanlosser
@wvanlosser Год назад
Nice video! Looking forward to the next one.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
What did you like the most about this one?
@wvanlosser
@wvanlosser Год назад
@@MilanJovanovicTech I've been reading and watching alot of DDD and Clean Architecture related content, but most content start from scratch. It was nice to see what steps you took to move from an anemic model to a rich model. One thing that I do struggle with is that most examples are relatively simple (models with but a small number of properties). I can see these model classes exploding when the models become bigger. Maybe that's also a sign that the model isn't correct (maybe doing too much in one place). Would love to see some more complex examples, although I can understand that those might not be very good for learning people new stuff. Anyway keep up the good work! I'm really enjoying the content so far and you explain things very understandibly. Also the pace and length of the videos are very good in my opinion 😃
@Mafyou75
@Mafyou75 8 месяцев назад
Insted of returning null, you can use the keyword "default". And thank you for your work Milan :-) you are doing good !
@MilanJovanovicTech
@MilanJovanovicTech 8 месяцев назад
Thanks for the idea!
@fernandocalmet
@fernandocalmet Год назад
Beautiful content, you have helped me improve aspects of my domain implementation. Please continue to release more content Milan, this type of content motivates me a lot in my professional career. Thank you very much for your contribution!
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Hi Fernando, I'm happy you like the video. Which part made the biggest impact on you?
@samehkeshta89
@samehkeshta89 Год назад
Great tutorial, keep it up.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Thanks a lot!
@dandoescode
@dandoescode Год назад
Another excellent video Milan. Watching you do the migration piece by piece is a really easy way to understand the differences between an anemic and rich data model. Which is the next video you eluded to? Domain events or outbox?
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Domain events, then Outbox
@timurrozhok2685
@timurrozhok2685 8 месяцев назад
A definitive *bold like* for this one! One thing that bothers me in this rich domain implementation, and not explicitly mentioned in video, - is that the time retrieval logic moved from the application layer to the domain one. In this example the domain just takes UTC from system clocks, but it may not be the domain's responsibility (and authority!) to act this way. The most suited implementation of a time provider may depend on a specific environment, but higher layers have no control over it now.
@MilanJovanovicTech
@MilanJovanovicTech 8 месяцев назад
Agreed, I kind of "hacked" it for time as I didn't want to bother. But you can either provide at as a method parameter, using a custom ISystemTime abstraction, or the .NET 8 time provider thingy
@timurrozhok2685
@timurrozhok2685 8 месяцев назад
@@MilanJovanovicTech Thanks for the reply! I wish you inspiration and creativity for your incredible work!
@hlazunov
@hlazunov Год назад
I would recommend reading about DDD starting from Von Vernon's "red" book and then reading Eric Evans's book.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
I've read Eric's book, but haven't read the one from Vaughn yet.
@NatalyaShtikel
@NatalyaShtikel Год назад
Thanks for great video, Milan! 15:07 Since the actual object being returned above is still a List, a caller may cast the result to a List and then add or delete an invitation. Because of this, you should use read-only wrapper by calling .AsReadOnly()
@MilanJovanovicTech
@MilanJovanovicTech Год назад
I tried, won't compile 😅 Do you have a working example?
@alexwexov4298
@alexwexov4298 Год назад
Great video !
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Thanks!
@pcclrocks
@pcclrocks 11 месяцев назад
Hi Milan, love your videos. I am learning a lot. I would like you to consider changing a setting in your Visual Studio. In Tools -> Options -> Projects and Solutions, select "Track Active Item in Solution Explorer". I suggest this because you move so fast from one class to another. This would help some of the viewers to better identify in which class you are working. Thanks and keep up with the good work.
@MilanJovanovicTech
@MilanJovanovicTech 11 месяцев назад
This is a year old video 😅 I'd say I'm doing a much better job at it now
@IcaroFelix2023
@IcaroFelix2023 9 месяцев назад
I found your content first by LinkedIn, and I really want to say that you are an amazing teacher.
@MilanJovanovicTech
@MilanJovanovicTech 9 месяцев назад
Glad you think so! I really appreciate that!
@mwaseemzakir
@mwaseemzakir Год назад
Before going to bed I preferred to watch this video instead of listening to music 😍
@MilanJovanovicTech
@MilanJovanovicTech Год назад
This is a first for me 😁 I hope that you enjoyed the video and found it impactful!
@VladaNish
@VladaNish Год назад
Great job and another great video.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Thanks! What did you like the most?
@VladaNish
@VladaNish Год назад
@@MilanJovanovicTech practical train of thought and the way how it was presented.
@VladaNish
@VladaNish Год назад
BTW, as per sending email and saving data in db, old way would be wrapping with transaction and commit that one when email is sent successfully but I find it a bit ugly (commit may also fail), I would prefer something like hangfire or quartz (they can fail / keep failing but it's "cleaner")
@33bgatti33
@33bgatti33 Год назад
Thanks for the wonderful videos you have posted on RU-vid. I'm working on a large-scale WPF application, and I've decided to do a DDD design for obvious reasons. However, I struggle with limited contexts and some potential circular references. Let me clarify: I'm working on an application that will measure traffic lights in a production process. The app will also include some serial number generation and other business related stuff. due to size and complexity, I decided to have three projects in the domain layer. Domain.Shared (base classes for Aggregate, ValueObject, Result ...) Domain.Measurement (logic for calculating product measurement results) Domain.SerialPort (Logic for SerialPort, where I specify specifics and client commands). Domain.SerialPort is boundedContext because the user must specify these settings in the user interface, and there are constant changes and versions of the product. The problem I have is that I want to specify a two-way property in EF. if i want to do this i need a field from Domain.Measurment to Domain.Products and a field from Domain.Products to Domainain.Measurment which creates a circular reference between projects. Another option I have is to inherit the entities in the persistence layer and just add the two-way fields there. what would your suggestion be?
@MilanJovanovicTech
@MilanJovanovicTech Год назад
You said you're treating these as separate *bounded contexts*. Then simply define duplicate entities, inside of each bounded context, with the required information. In your EF Core configuration, you can make them use the same database table. Does that make sense?
@33bgatti33
@33bgatti33 Год назад
@@MilanJovanovicTech Thanks you Milan, It makes a lot of sense to do so. When configuring EF Core i just need to add same name into ToTable property.
@nettoaoquadrado
@nettoaoquadrado Год назад
Amazing!!!
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Thank you! Cheers!
@tplummer217
@tplummer217 9 месяцев назад
Excellent
@MilanJovanovicTech
@MilanJovanovicTech 9 месяцев назад
Thank you so much 😀
@nouchance
@nouchance Год назад
Thank you Sir! Amazing:))
@MilanJovanovicTech
@MilanJovanovicTech Год назад
I'm glad you liked it. What is your biggest takeaway from this one?
@issacproton7885
@issacproton7885 Год назад
Wow...Awesome...just loved it...please keep it up for the community who encourage to learn....please make a video on productivity shortcut on visual studio if you could so that everyone can get more benefits out of it.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
The best productivity hack is: ONLY USE THE KEYBOARD. This will force you to learn all of the keyboard shortcuts, and you will be much faster. Guaranteed.
@issacproton7885
@issacproton7885 Год назад
@@MilanJovanovicTech hmm..strongly agreed!
@mahmoudalballah3387
@mahmoudalballah3387 Год назад
Awesome!
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Glad you think so!
@shivamdeshmukh852
@shivamdeshmukh852 2 месяца назад
I thoroughly enjoyed your content and wish I had discovered it a year ago. Your explanation of concepts is both precise and on point. My only suggestion is to consider developing a structured path that guides learners from creating projects from scratch to a level where they can confidently produce a fully functional application, perhaps through a series of 10 videos progressing from beginner to advanced levels.
@MilanJovanovicTech
@MilanJovanovicTech 2 месяца назад
Welcome aboard! And that's a great idea :)
@marcinaumiler3722
@marcinaumiler3722 Год назад
Hi Milan, you have truly great skills to deliver somewhat complex content in clear and concise way:) I've got two question (unless you already covered those in another video): 1. What do you think about abstracting away dependency on DateTime in your domail model (e.g. to make testability easier)? 2. What is your opinion on returning types from your methods representing commands (e.g. Invite) instead of keeping return type void and follow CQS.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
1. I agree that would be a good idea, but I didn't want to bother with it at the time 2. I'm not sure what that would look like. Have any example?
@peymanebrahimi7756
@peymanebrahimi7756 Год назад
Thanks for great content. Saga can be used for db saving and sending email transactions. Masstransit would be a great content to cover. I really appreciate the concise and excellent way of explaining.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Thank you for the content suggestion!
@hosseinnarimanirad2953
@hosseinnarimanirad2953 Год назад
Good! wasn't it better to call AsReadOnly method to return IReadOnlyCollection. This way (not using this method) clients may simply cast the collection as List and modify it
@MilanJovanovicTech
@MilanJovanovicTech Год назад
ToList will return a new list, different memory reference. And you can't cast it. Did you try?
@hosseinnarimanirad2953
@hosseinnarimanirad2953 Год назад
@@MilanJovanovicTech Where did you use ToList? In this video you simply return the backing field in the getter. Anyway I think its better to return the readonly type to emphasis that the client cannot change it.
@nothingisreal6345
@nothingisreal6345 Год назад
Rule of thumb: whenever you write a couple of lines that all do obj.Property= or obj.DoSomething() - consider moving that code into the implementation of the object - especially if you do the same or very similar changes elsewhere. Certainly, a property like NumberOfAttendess (which is redundant as it is equal to the count of the list) must never be writeable from outside.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Good point, that way when you add a new property you only have to change that one method.
@MdArifulIslam-ov9yd
@MdArifulIslam-ov9yd Год назад
Awesome ⚡⚡⚡⚡👍👍
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Thank you! Cheers!
@Swzvtlbngfd
@Swzvtlbngfd Год назад
Thank you for this wonderful video showing step by step, moving logic from Command Handlers to Entities itself. I have a query on implementing the same for Database First approach where the DB is already created for us. In such cases,we auto generate the entities using Scaffold-DbContext command and every time there is change in DB design, the entities are auto generated. How to tackle those situations? Do we put all domain logic in separate partial classes? Thanks again for this series.. I have been using N-Tier architecture for so long that this is a whole new fresh air of learning and I am very happy to be able to learn this new architecture.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
You can even create your Domain entities as separate classes from your persistence entities. You would have to handle mapping between the two, however.
@arunbm123
@arunbm123 2 месяца назад
very brilliant Video...
@MilanJovanovicTech
@MilanJovanovicTech 2 месяца назад
Many many thanks
@Embriiii
@Embriiii Год назад
Another step could be encapsulation of the wole collection into an "Attendees" class. I'm curiouse about a video on Domain Services, maybe with the distintion about impure and pure domain services. 👍
@MilanJovanovicTech
@MilanJovanovicTech Год назад
I haven't done custom collections. What do you think it brings? Domain Services video is a good topic, I'll add it to my list.
@JLPA42
@JLPA42 Год назад
Thanks for the video. Is there any added value of using a static factory instead of new Gathering()? The switch/case statement can be a method of the Gathering entity that is called on the constructor as part of the minimum validations in order to build a valid Gathering.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
You can get some fun behavior with ORMs and constructors with logic. EF for example will find the best constructor (even a private one) to create a new instance of the class. I was bitten by this before, so I tend to be cautious. Also, sometimes it's quite useful for your factory method to be async. For example, if you pass in some service interface to perform a check. In this case you can't use a constructor at all.
@ugochukwuumerie6378
@ugochukwuumerie6378 Год назад
NIce content, await NextVideoAsync(). For the email part (hope this is not an overkill), you would probably use the Mediatr notification and publish to something that is not on the main thread and might not be awaitable like hangfire or an In Memory Background Service to handle retries even if it fails.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
That's exactly the idea. I want to show how we can use the Domain Events pattern for offloading certain tasks to the background.
@ugochukwuumerie6378
@ugochukwuumerie6378 Год назад
@@MilanJovanovicTech Awesome 👌
@jakubsuchybio
@jakubsuchybio Год назад
Hi, just a dev tip: when you were replacing that constructor parameter invititationsValidBeforeInHours, you could do a multi-cursor there with Ctrl+D 2x times for the 3 occurences and not 3x times navigating with a mouse ;-) but maybe you already know this after 9months of publication of this video
@MilanJovanovicTech
@MilanJovanovicTech Год назад
You sometimes forget things like that when you record videos 😅
@alibabarahaei2229
@alibabarahaei2229 9 месяцев назад
perfect
@MilanJovanovicTech
@MilanJovanovicTech 9 месяцев назад
Thank you!
@rodrigoramirez1031
@rodrigoramirez1031 Год назад
Hey Milan, great content! thanks for sharing. I've seen before that instead of having the repository independent of the unit of work (as you do on your video) there are people that implement it in a way that the unit of work contains the repositories such as: _unitOfWork.PersonRepository.AddPerson(person) Any thoughts on that? just curious! Thanks!
@MilanJovanovicTech
@MilanJovanovicTech Год назад
I like separate repository interfaces because then it is obvioud which queries you can find in a command handler for example. With UoW + Repo combined it's not as obvious.
@MickaelLY
@MickaelLY 7 месяцев назад
Great tutorial and awesome channel ! @11:09 why do you leave the guid as a constructor parameter ? Is that a bad practise to generate the guid directly in the constructor itself?
@MilanJovanovicTech
@MilanJovanovicTech 7 месяцев назад
I like to generate IDs client side when using Guids
@UberEverywhereSKRT
@UberEverywhereSKRT Год назад
Hi great video ! I have two noobie question : 1) at 9:32 , in the SendInvitationCommandHandler, you create an invitation then you add it to the gathering.Invitations list (line 63) then add the invitation in its repo then SaveChanges(). What is the purpose of doing both? Cant we just add the invitation to the repository and SaveChanges OR add the invitation to the gathering.Invitations list and just SaveChanges since EF is tracking? 2) at 24:00 cant we just keep List Attendees but give it a private set? Instead of making it a ReadOnlyCollection and create whole new field private? Ty so much in advance!
@MilanJovanovicTech
@MilanJovanovicTech Год назад
1. The first part will be enough for EF. I'm adding it to the repo just to make it more robust. Can easily be left out. 2. Yes, we can go with that approach.
@mohamedasem6523
@mohamedasem6523 Год назад
great video, I want to know what's the alternative for returning null, did you make a video for that?
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Return a Result object
@Pest87
@Pest87 10 месяцев назад
An excellent video. What do you think about the opinion that domain driven design works well only if we know all of the project's business logic from the beginning and that this rarely happens in the real world? And some folks claim in such situation it is better to use the more old school multi layer architecture with presentation, business and database layers and annemic models. It would be great if you can shoot a video about comparing the pros and cons of both.
@MilanJovanovicTech
@MilanJovanovicTech 10 месяцев назад
I think your domain model needs to (and will) evolve over time. Nobody starts with a complete domain model. You end up with one, after many iterations.
@michamularczyk7372
@michamularczyk7372 9 месяцев назад
Great video, thank you. One question to 24:30. Shouldn't logic defining rules for calculating whether invitation expired be considered as some kind of business logic and thus belong to Application instead of Domain layer?
@MilanJovanovicTech
@MilanJovanovicTech 9 месяцев назад
Business logic does belong in the Domain
Год назад
I prefer when business logic is everywhere, yet clearly identified. For example, the presentation layer could know the format of a US zip code. I prefer when layers are not distinct projects (file). A class could be able to talk to DB via basic interface eg. DAO. Well I also like to go for twho parts: Backend (endpoints) and frontend (CSS+HTML+Javascript).
@MilanJovanovicTech
@MilanJovanovicTech Год назад
What's the benefit of having business logic everywhere?
Год назад
@@MilanJovanovicTech Speed, and I also duplicate the logic once in the stored proc and once in the front of back end - no need to hit the db to know something is invalid and another foreign application or user may run the [safe] stored procedure without proper up-front validation. I'm for simple code (fewest indirections, little or no function/class injection).
@wellyngtond2
@wellyngtond2 Год назад
I think, for the case of "sendEmail" error, the best approach would be put the email in a queue or in a table to some cron job get end send it.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Yup, that's the proper approach. Store it somewhere, and process it later.
@rezarezash
@rezarezash Год назад
Thanks for the videos and effort - Just a comment -The video is supposed to cover the domain but you started with the application and commands - Also, it could be more helpful if you create the domain entities step by step or at least a couple of them. Thank you.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Take a look at the other videos also
@danilodjokic5303
@danilodjokic5303 Год назад
Milan, what is in your opinion the advantage of having a static factory method instead of implementing the full factory pattern ?
@MilanJovanovicTech
@MilanJovanovicTech Год назад
With a static factory approach I have access to private/protected methods on the Entity. I tend to use this fact to simplify the behavior by having smaller methods. Also, I'll show an example of static factory with domain events. I didn't find much use for the full factory pattern. Perhaps I didn't run into a problem that really needed it.
@davorzganjer5291
@davorzganjer5291 4 месяца назад
Nice video, self-explanatory. In this case, business logic is encapsulated in the domain model and it's not dealing with DB but let's assume that business logic needs some interaction with DB, meaning if-else would call different DB logic (repository). By design, we can't inject a repository to get needed data but how would you approach DB interactions from your domain model?
@davorzganjer5291
@davorzganjer5291 4 месяца назад
I think I found it ru-vid.com/video/%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE-eC7GMGIR4Gw.html
@MilanJovanovicTech
@MilanJovanovicTech 4 месяца назад
There are three options, I talked about them here: ru-vid.com/video/%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE-eC7GMGIR4Gw.html
@user-ji7qu7bd4w
@user-ji7qu7bd4w Год назад
Great video, thanks, the short question, why do we use method name Gathering.SendInventation considering the fact that method does not perform any 'sending' logic and just add a newly created Inventation instance to the Gathering?
@MilanJovanovicTech
@MilanJovanovicTech Год назад
You are expressing intent via the method name. In terms of the domain, creating a new invitation instance is "sending the invitation"
@pburczyn
@pburczyn Год назад
​@@MilanJovanovicTech I don't agree with you :) the 'method name' should reflect what it does, not what the intention is (as a developer I would be confused if I saw a method name like that).
@rezarezash
@rezarezash Год назад
Hi Milan, Is there a separate video for the Application project?
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Closest is CQRS video
@marhoily
@marhoily Год назад
When you are doing data validation video, could you take an example of the nature of "there should be no 2 members with the same name\email"? I'm interested in how you are going to avoid the data racing condition, when there are 2 simultaneous requests to create a user with the same name. I understand how the optimistic concurrency works on the level of an entity, but what are you going to do when it is not practical to aggregate all the data necessary for the validation in one entity?
@MilanJovanovicTech
@MilanJovanovicTech Год назад
The next video will be more about Domain level validation. I consider the "unique email" rule more of an Application level validation, but I will definitely cover that in one of the coming videos. Thanks for the suggestion! As far as the implementation - here you can just rely on a unique index at the database level. It is atomic by design.
@zhivkopetkov4133
@zhivkopetkov4133 Год назад
I found you via LinkedIn, nice videos for sure, keep the good work
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Thank you very much. Any content wishes? 😁
@fxandrei
@fxandrei Год назад
Do you have a link with the book you mentioned about DDD ?
@MilanJovanovicTech
@MilanJovanovicTech Год назад
www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215
@vivekkaushik9508
@vivekkaushik9508 Год назад
Which keyboard do you use? I really like the sound of it. Blue switches?
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Nothing fancy: Logitech K120
@Skuerke95
@Skuerke95 Год назад
For the gathering, you can just use a record. No need for private setters or separate ctors.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
But then you end up with an Anemic and Immutable domain model. How will that work?
@odoolabs1366
@odoolabs1366 Год назад
Good explanation I am following your tutorial but I have one question you put send invitation inside gathering class isnt it against S of Solid principles ? because our class is not only responsible for create gathering but also it is sending invitation ?
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Think of the Gathering as a whole. You can't apply single responsibility to absolutely everything out there.
@haruundk
@haruundk Год назад
How would you go about translation to different languages? I mean mostly static error messages etc.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
I would leave that for the frontend most likely
@sajagjain7169
@sajagjain7169 Год назад
Hi Milan, Is there a way to restrict private fields assignment in certain cases within the model? Context: Hypothetically if I save age and birthday both in db anytime I update birthday it should update the age. But anyone within the model can still set those fields by directly assigning values to the private fields.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Not much you can do about that. But consider this: if someone is setting the value of a private field - you will know. You can't really miss that in the code, so you're much more likely to catch it and fix it accordingly. Right?
@sajagjain7169
@sajagjain7169 Год назад
@@MilanJovanovicTech I agree with you. Do you think having a convention here might help??
@DeejayWazzouille
@DeejayWazzouille Год назад
Hi ! I read that ctor should be private in model to avoid creating anywhere except in the model himself. But how do you convert object coming from databse (objectDTO) to the object domain model without a public constructor ? I could use create, but it doesn't work with the ID property which shouldn't be changed
@MilanJovanovicTech
@MilanJovanovicTech Год назад
You can create a factory method for that
@ravindranathwi
@ravindranathwi Год назад
I see return Unit.value where is that. Can't see it in the class anywhere
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Coming from MediatR library
@Eless88
@Eless88 Год назад
Hi, Milan I'm not sure, that changing the Invitation's properties inside of the gathering is a good way because it looks like a side-effect. I think, that the Gathering class should only have the possibility to check the expiration and AddAttendee(attendee) method
@MilanJovanovicTech
@MilanJovanovicTech Год назад
You can model it how you think is best, I think I explained my reasoning for why I chose to do it like this
@mattmarkus4868
@mattmarkus4868 Год назад
A Gathering does in fact own the Invitation. You can't have an Invitation without a Gathering, it wouldn't make sense. But a Gathering object can have no invitations, that seems totally valid. It makes sense to me to isolate that. I don't know what you mean by side effect. Why have multiple ways of creating or changing an Invitation that's not known by the parent Gathering? What is this side effect concern?
@mattmarkus4868
@mattmarkus4868 Год назад
@E1ess , it's also good encapsulation of any logic required to create/send an invitation. It's all nicely hidden inside the owner Gathering instance. That is further illustrated by making those children a read-only collection. All a user can do is say, "SendInvitation() and return it to me. Whatever it does I don't care". And that allows that logic to change without affecting users (although, it is core logic and isn't likely to change but if it does it changes for all applications using it). The Handlers is where app-specific logic goes. Domain-specific logic goes in the domain layer. I like this channel so far.
@kauegatto
@kauegatto Год назад
Might be a really really dumb question, however, let's suppose I want a User Crud, in this more spefic scenario I want to create an User account. Then should the Controller instantiate a User (by using the Controller) and then pass the User object to the repository and have faith on the User validation since an error wasn't thrown? Also, what do you think of Services? When should we create them? I've heard of some people that Services should be an action (verb) that makes use of different domain objects.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
I'm unsure about your first question, but if I understood correctly: The approach with Controllers is fine if you want to place logic in controllers. I use services mostly to abstract external services. And occasionally as domain services. Domain services to encapsulate some business logic, jo external concerns.
@sahinhanay3692
@sahinhanay3692 7 месяцев назад
Isn't writing logic in the entity class against solid's s principle? Doesn't it make more sense to apply the factory pattern in a separate place?
@MilanJovanovicTech
@MilanJovanovicTech 7 месяцев назад
Not in DDD
@emmanuelcaulin4395
@emmanuelcaulin4395 2 месяца назад
Do you use async every time you call db operations even if it only returns 1 row of data or 1 column?
@MilanJovanovicTech
@MilanJovanovicTech 2 месяца назад
Yes
@adisilagy
@adisilagy Год назад
Hi Milan, In this video you created a static method responsible for creating a gathering entity. How would you create the gathering entity when getting the records from db using Dapper. If I am not mistaken the Dapper mapper will not be able to create the entity right?
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Indeed, this approach would be tough to work with for Dapper. With EF it works without much trouble. You can get by with a factory method for Dapper. So fetch the raw data from SQL, and then pass it to your factory to construct the entity properly. Alternatively, you can build entity factories in the Domain layer - but it'll end up being a lot of code with little benefit.
@adisilagy
@adisilagy Год назад
There are a lot of options regarding using Dapper or EF. I would like to hear yours. From your videos I understand that you are a fan of EF, but I also heard you say in two of your videos that for boosting performance you would use Dapper.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
@@adisilagy Just create a static method that accepts primitive types. Load from database using Dapper. Call the static method, which will transform values into rich domain model. Perhaps I should make this into a video?
@adisilagy
@adisilagy Год назад
@@MilanJovanovicTech it would be great if you can create one
@adisilagy
@adisilagy Год назад
@@MilanJovanovicTech I think that a general video showing how using Dapper with the repository pattern and rich domain model would be an interest to many developers
@IAmESG
@IAmESG Год назад
Now that's the true DDD
@MilanJovanovicTech
@MilanJovanovicTech Год назад
🔥
@mgame8082
@mgame8082 Год назад
Which program are you using for drawing class diagram? 1:10
@MilanJovanovicTech
@MilanJovanovicTech Год назад
draw.io
@tiagocandeias3969
@tiagocandeias3969 Год назад
@Milan Was reviweing this vídeo and I need to ask. What tool you use to make the class diagram in 1:20?🤣 Thank you
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Hey Tiago :) It's built with draw.io but there's a setting to make it look "cartoonish" 😁
@tiagocandeias3969
@tiagocandeias3969 Год назад
@@MilanJovanovicTech I have to look for that setting, those look awesome!
@cdsmith8528
@cdsmith8528 Год назад
I'd be interested in if you are going to raise the issue of, when you are submitting updates, to not allow an invalid domain entity to be constructed - ie, not applying updated values to an entity unless you can first validate that the new values won't put the entity into an invalid state especially when dealing with complex aggregate entities.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
My approach is to enforce these kinds of constraint by design. Your domain should expose such an API that you can only create entities in the correct state, and also be allowed to only update them into a new correct state. How do you approach this?
@cdsmith8528
@cdsmith8528 Год назад
@@MilanJovanovicTech I prefer to do the same thing; enforce by design. In the past, I have had to retrieve the aggregate entity and generate a DTO and send that along with the command object with the new values to a business rules engine where all validation was kept as a separate system.
@ThingsTK
@ThingsTK 4 месяца назад
are both the domain model and entity model (EFCore model) same? is there any difference in domain model and entity? generally my entities are suffixed with Entity (InvitationEntity) and domain without any suffix.
@MilanJovanovicTech
@MilanJovanovicTech 4 месяца назад
I keep them the same when I can, less things to manage
@ThugLifeModafocah
@ThugLifeModafocah Год назад
What is the problem of the logic inside de constructor or inside of the static factory method create? Why one approach is better than the other?
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Constructors can be called by ORMs, for example EF Core does that. So if you place something wide a side effect in the constructor it can lead to undesired behavior.
@ThugLifeModafocah
@ThugLifeModafocah Год назад
@@MilanJovanovicTech humm, got it. Thanks for the answer.
@randallhodgson447
@randallhodgson447 Год назад
In minute 15:33 why would you add the invitation to the _invitations list if you already add it in the repository afterwards?
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Just for safety, but with EF Core it's not necessary
@max_gus
@max_gus Год назад
At 22:10 why do we move invitation accept logic to the gathering entity? In my mind accepting an invitation is not responsibility of gathering object
@MilanJovanovicTech
@MilanJovanovicTech Год назад
I'm looking at the Gathering as the aggregate, and want to enforce all operations through it. Of course, you can design the domain in the way you propose and there would be nothing wrong there.
@ghaiathaltrabulsi135
@ghaiathaltrabulsi135 Год назад
Thanks Milan. Shouldn't the commands and queries live in Domain and theirs handlers live in Application? Is there any wrong with this approach?
@MilanJovanovicTech
@MilanJovanovicTech Год назад
I don't agree with that school of thought. To me, use cases - under which I also count commands/queries - fall under Application level concerns.
@glauberbrennon
@glauberbrennon Год назад
@@MilanJovanovicTech this is an interesting topic! when we talk about "plain hexagonal architecture" we would put those definitions in our "core" layer bcs this module wants to define everything from the inside-out! but when we talk about, what i like to call, "cleanxagonal architecture" everything related to "commands" or "queries" should be defined in the application layer
@patrykklimas4398
@patrykklimas4398 Год назад
What do you think about defining repository interface in the Domain layer?
@MilanJovanovicTech
@MilanJovanovicTech Год назад
I think it's perfectly fine since it's only a data contract. And the way I use it to return only entities, so there is no pollution of the interface with other classes
@user-yx4po9tt8z
@user-yx4po9tt8z 4 месяца назад
I couldn't understand why did you something like that with Lists (in 15:18) I think that EF core can handle all of them... or may be you did this because you wanted to use other ORMs like dapper? also i dindn't like adding SendInvitation into Entity... i think it's a buisness rule, and I have to implement that on application layer. note that: i'm not a native guy so some times i can't translate my right meaning i'm Sorry if I was disrespectful, I like your videos very much
@MilanJovanovicTech
@MilanJovanovicTech 4 месяца назад
DDD is about pushing business logic to the domain. So that's the motivation behind the decisions.
@user-cp8eh7ku5q
@user-cp8eh7ku5q 2 месяца назад
Thanks for the video. What is the best way to avoid god objects in that kind of architecture? What if I have a domain entity that used in dozens of different scenarios? Isn't it too much for one class to contains the whole business logic related to the entity? How would you segregate and handle with domain entities which have a lot of fields, methods, and different constructors?
@user-cp8eh7ku5q
@user-cp8eh7ku5q 2 месяца назад
can you share a video if you have about that topic
@MilanJovanovicTech
@MilanJovanovicTech 2 месяца назад
Wouldn't the methods be relatively small in that case?
@MayurNagrale
@MayurNagrale 10 месяцев назад
Can anyone help me create that project structure where inside solution we will be having src folder and and all the project inside that src?
@MilanJovanovicTech
@MilanJovanovicTech 10 месяцев назад
Just add a solution level folder in VS
@tanvir.programming
@tanvir.programming Год назад
Good video! But one mistake. Keep a private parameterless construct in every entity for serialization and EF query mapping.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Are you sure it's a mistake? Maybe I did it on purpose? 😉
@syedib
@syedib Год назад
I guess Millan will not use EF Dbcontext to query from DB.. instead he will use Raw sql Query for reading data and map them into Custom class
@newraze
@newraze Год назад
@@syedib as i think the reason is that plain sql commands are more accurate and faster than EF for reading data (of course if its written well)?
@nobel03
@nobel03 Год назад
How do you handle domain objects and persistence? Because a domain object's structure may not be suitable for relational DB persistence.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
I try to not think about persistence when designing my domain model, because it will be constraining to design an ideal domain model that way. However, I will show you how to convert this domain model into a normalized relational model in one of the future videos!
@tienlam5599
@tienlam5599 Год назад
@@MilanJovanovicTech Is that so you will design domain objects before persistence ? Then convert from domain objects to persistence ?
@MilanJovanovicTech
@MilanJovanovicTech Год назад
​@@tienlam5599 That's why it is called "Domain-Driven". The point is that if you concern your self with persistence while modeling your domain, you will make some decisions that impact your model so that it can be translated to a certain database model. This goes against the point of using DDD. I will show you in a future video how to persis this model using EF, it's not so complicated.
@jacobnunez7678
@jacobnunez7678 11 месяцев назад
Hi Milan, could you recommend me some books about clean architecture and cqrs?
@MilanJovanovicTech
@MilanJovanovicTech 11 месяцев назад
Clean Architecture by Uncle bob
@jacobnunez7678
@jacobnunez7678 11 месяцев назад
@@MilanJovanovicTech Thanks.
@MDP1366
@MDP1366 Год назад
Hi Milan, Thanks for this awesome video. By the way, I want to mention that your code heavily violates SRP and OCP.
@MilanJovanovicTech
@MilanJovanovicTech Год назад
Care to explain why that is? That would be the least you can do when criticizing someone's work 😁
@MDP1366
@MDP1366 Год назад
​@@MilanJovanovicTech First of all, Big fan, I really like your video. Now as a developer, for example, the Create methods of the Gathering class violates SRP because it does more than one thing and the abstraction level is not the same, also because of the switch case in the method, if you need to add new GatheringType, you need to change the function. It violates OCP. And so on. By the way, I really don't want to criticize anyone, especially those who try to teach something new to others. 🌻
@MilanJovanovicTech
@MilanJovanovicTech Год назад
@@MDP1366 I'm always open to a nice discussion! How does it do more than one thing? It just creates a new Gathering. As far as OCP, I agree. And there are ways to go about that. But I don't think it's necessary to dogmatically follow every pattern and principle out there. You have to be pragmatic about it, and not add too much complexity.
@MDP1366
@MDP1366 Год назад
@@MilanJovanovicTech I do not agree about the dogmatic part and also OCP/SRP is not every pattern. these are for better codding style but I do agree that simplicity is ultimate satisfaction :) I have a suggestion, if you don't mind, we can arrange a video call or something and work on it together, maybe you changed my mind :)
@glauberbrennon
@glauberbrennon Год назад
​@@MilanJovanovicTech i understand both points of view. we could change from a big factory method to some factory class that would use that "GatheringType" argument to select which "Gathering" factory method it wants to execute using this approach we wouldnt need to touch the same code everytime we need to add a new "gathering type" preventing us from "changing" old code
Далее
How to Use Value Objects to Solve Primitive Obsession
13:54
What is DDD - Eric Evans - DDD Europe 2019
57:06
Просмотров 255 тыс.
Onion Architecture vs Clean Architecture Comparison
13:44
Domain Driven Design: What You Need To Know
8:42
Просмотров 99 тыс.
The Smart Way of Using the Decorator Pattern in C#
12:37
Clean Architecture With .NET 6 And CQRS - Project Setup
12:40
Forget Controllers and Minimal APIs in .NET!
14:07
Просмотров 53 тыс.
🛑 STOP! SAMSUNG НЕ ПОКУПАТЬ!
1:00
Просмотров 71 тыс.
🛑 STOP! SAMSUNG НЕ ПОКУПАТЬ!
1:00
Просмотров 71 тыс.