Mini Course #1 Clean Architecture + CQRS

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
so clean architecture mini course take [Music] free youtube it's derek from devmentors and yeah here it is finally we we've managed to to deliver something so this is the first of two announced mini courses here on the youtube and this one as you can already see is about the clean architecture and cqrs the other one will be handled by peter himself and it's going to be around christmas time hopefully so by the end of the year you should get both this and peter's material so we are thankful for for all your support and we hopefully hopefully you'll like both videos and you will find it useful in some way and yeah i've got the notes in here so sorry for some that i will sometimes look at them but i don't want to skip anything uh yeah i think that before we actually jump into the topic i would like to just briefly discuss the history behind this clean architecture stuff because actually this material was one of the reasons why we didn't deliver further our modular monolith series and the reason is very simple we've kinda finished the i think two modules in there and both of them were pretty much crud ish there was no that much i would say domain logic it was rather simple when it comes to domain the idea was just to give you some sort of start starting point and we wanted to wire them using the asynchronous integration and yeah that we delivered however at some point we wanted to introduce something more robust when it comes to domain and part of that material was dedicated to clean architecture the issue though was that we yeah we covered the clean architecture on during our micro microservices.net course so not the dshop one that we have here on our youtube uh but rather the one which is available on our platform so clean architecture was one of the topics that we covered them and yeah we we felt like okay we are going to discuss exactly the same thing so for the people who are already familiar with the concept they will need to skip this and this will not bring any value and the other thing was that we thought that the clean architecture itself it's not tied to modular monolith it could be just a regular monolith this could be a microservice anything so we kind of were scared about the fact that this could be lost in this modular monolith series and even and maybe this could bring a you know it could bring a value to someone but if you haven't followed the whole series maybe you'll basically you know not get into this one so we decided that it's the best to basically extract this put into separated video and we could refer to this from different materials so there will be no need for repeating every single in every single course the same sentences because it makes no sense for us it's not fun for us and it would be just you know making the videos longer and longer in that case we'll have this material if you know at any point in the in the future we'll need to reference and we will need to mention the clean architecture we'll just say okay this is the video go watch it if you don't know the concept simple as that so without further ado i think that we are now ready to the theory first i would like to just briefly discuss first the concept that you might be already familiar with and that was partially mentioned in the trailer so the layers architecture and then we'll try to compare it to i would say uh yeah the one that you came for so for to the to the clean architecture so first things first i will use the term layers architecture quite often in this video so i think that it's good to first think about some sort of definition just will so we'll be on the same page so what i mean by the layout architecture is this very specific setup in which you have at the very bottom data access layer and yeah data access layer as the name says is basically the layer responsible for your data access in like 99 this would probably be the database but yeah there might be a situation in which you store the data in the file system maybe you use some additional third-party web service like you know s3 or something blob storage whatever or the cloud provider so yeah basically we'll have some sort of layer that will be responsible for encapsulating this data access on top of it you'll have the application layer sometimes called services layer which for me it's like just a bizarre i mean calling something services is not very precise because service might be a different thing and might you know mean different things so application would be more suitable for me and and basically the application layer would orchestrate the whole process so that it will contain in this specific case i would say that it contains both process and domain logic and on the very top you have the presentation layer which could be kind of misleading for the web developers because you already when you think presentation layer you probably think about the ui so maybe there's some like you know razer pages like something else wpf or something related to the screen but basically you can think about this as some sort of entry point to our application so let's say for the mobile app this will be this might be some sort of project related to web sorry to the mobile screen uh maybe for the windows application this could be something like wpf maybe some sort of xamarin etc for the web developers especially if you're only specialized in the backend this will be just the web api so our our entry to system will be the web api so i will say okay if you want to perform certain action this is the end point this is let's say post method that you need to call so i would say this is briefly when it comes to the layer architecture and this is what i mean i know that there are different types of player architecture but the one that i'm going to discuss is this specific setup which i found pretty popular at least a few years ago maybe that's specific to poland so the country where i live maybe but i don't think probably not now i don't want to get into the history of why this could be very popular etc i would like to focus on the stuff that i don't really like about it because honestly there are not many things that i really like um it's rather simple it's rather no brainer does not require a lot of knowledge so you could think about this as some sort of advantage of this approach but on the other hand there are quite a few more critical disadvantages that should be discussed first before we move into the clean architecture and we could see how this actually solves those issues so the very first thing would be the fact that this whole approach to me is rather data centric and to give you the some sort of retrospective from my own life how do i interpret this um yeah i would just like to briefly talk about my first greenfield project that i was involved in and that was the time when i yeah i was wasn't very experienced and that was the time when i was referring to trailer of this course if you haven't seen then there is a card you can i can watch this 10 videos 10 minutes a long video during which i make myself an idiot but honestly at the very beginning of this trailer there was a title that said that this is kind of based on the facts and the reason i put this title was because i used to be a kevin i used to be a guy who yeah thought that the architecture is like you know state of the art of course that was because of i was not experienced i didn't have enough knowledge and i didn't see a lot of disadvantages of the layout architecture approach and what is crucial to this whole story is that at that point and i think this is pretty common when it comes to junior developers is that i favorite technicality and technical stuff over the domain and over the business value that i was hired for and the second thing was that i would honestly say that at that point i didn't get very crucial concept which is the model or the object that you have within your application let's say product if you have the class name product it doesn't necessarily be just one ultimate representation and which is used for data access for let's say databases for the application for the domain and for the transportation there could be different representations and you just need to map between them but at that time i basically thought okay i've got one ultimate model which i need to this needs to be reusable in database and in different layers so this actually caused a lot of issues and yeah let's just jump into the story and hopefully you will see you will see what i mean by the by this and you will also understand hopefully the what i mean by the data centric approach when it comes to layered architecture so when i started this project and um yeah we actually received like we in the trailer received like half page briefing and so you can ex you can already see that my knowledge about the domain and what we are going to do was very limited and of course we had like meeting scheduled during which we wanted to discuss the the requirements and what we actually want to achieve by doing this application yet still once it got it got announced the very first thing i started doing was the thing which was for me at that time the most important when it comes to the software development and that was the database and yeah the the issue was maybe not the issue but the reason for this was very simple i mean for me the application was just the facade between the database and the client and that was it you know if you're clicking a button save eventually this gets into the database if i'm getting button get data the data comes from database so for me the database was the heart of the application and yeah i started doing these diagrams i was i think at that point i just graduated i think my bachelor so i'm not quite sure but yeah i i still remember this whole notation and i created the diagram on the paper first later i use i think some sort of software for for those diagrams and yeah i was very proud of it and of course almost none of those concepts on those relations got into the production at the end of the day but at that point it didn't really matter i mean i was really into those databases and of course i was using the relational database relational model because i didn't know any other and i thought that this basically can solve any issue in the world so yeah i already knew that i'm going to use the sql server i already knew that this would be relational database and i've got my diagram on paper and yeah and then the natural continuation was the code base so i started to develop the application and that's where i kinda i would say that the alert architecture kinda helped me in a bad way to develop this whole crap because if you think about those layers so data access layer application and the and the presentation there are two possible ways of implementing it so the first one would be going um i would say top down so you start with the controllers and then you go to the application service the application layer and to the data access layer however it doesn't really work because as soon as you will start writing your controller actions you will realize that okay but this action is supposed to call the application layer yet still i don't have the implementation so you need to go to applic to the application layer write the at least abstraction but ideally we probably would like to have some sort of implementation already and yet still you will realize okay but this application layer orchestrates and yeah it needs the data access layer so you need to go to the data access layer implement it and eventually you can finish up the application layer and the controllers so i would say that the top down approach doesn't really work so at that point for me it was way better to go bottom up not only because you don't have this issue with dependencies but also since i already started with database first approach the code that was closest to database in the application code was data access layer yeah so i was doing this and yeah at that point we used like entity framework for i guess maybe five so me as a junior developer i went to msdn and i was reading the documentation and i've seen this and yeah i mean this is perfectly legit right you have the classes with public getters and setters no methods and this is how you create your entities and as i mentioned to me this model this class was not only for database purpose but also for the domain and for the transportation and at that point i also didn't realize one crucial thing the whole purpose of this documentation is not to teach me how to create a proper architecture i mean this is created to show the capabilities of the orm and that's pretty much it and of course this rm might have some sort of limitations due to underneath implementation maybe they use some sort of reflection or something else and this is why everything needs to be public and i maybe you need to put the virtual make the property virtual or something else but at that point i didn't realize that to me though to me that was quite kind of natural that what is on the msdn is the state of the art and i and i cannot change it so yeah i finished the data access layer and once i've got it i could move up to application layer and of course because i had no encapsulation within my entities and i still needed to perform some sort of domain logic there yeah there needs to be a place in which i will put it right because otherwise this will and this will also will be responsible for preventing the further licking to the controllers i need to place in which i will basically encapsulate all those rules so naturally i came up with the services so this application slash domain services which basically were doing everything so orchestrating the process but also keeping all the validation rules and setting the proper values into my entities and that was that was it that was the whole point of my application layer and on top of that i've got you know like real regular asp.net core controllers and actions and they were not pretty contained some unnecessary logic also which i for some reason didn't put into the services but who cares right at that point i i really i really didn't and that was pretty much it and of course the reason for telling you this embarrassing story is to give you this flavor what i did it from the perspective of you know from today's perspective what i did it really don't like about this whole layered architecture approach is that it helped me focus more on the data and the technicality rather than on the domain and the behavior itself because i started from the technical layer technical technical concern and further the the domain and the orchestration of this domain was just an addition to what really mattered to me which was the database so that's the disadvantage number one and the second is actually more fun because this particular setup when it comes to layered architecture breaks one of the wholly solid principles which is dependency inversion principle so let me just go to the definition of the dependency inversion principle i've got the wikipedia page and of course you might ask why i'm reading this instead of just saying this from my head why i don't know it um well the reason is very simple i i honestly don't know the exact definition i follow the solids um naturally on my my daily basis but i don't know the exact definition i only know that uh before the job interview which i don't plan to attend at least at some closer time unless my unless my boss will see this video so dependency inversion principle says that high level modules should not import anything from low level modules both should depend on abstraction and there is also paragraph b abstractions should not depend on details details should depend on abstractions so when we think about this particular thing and this principle actually it doesn't fit into what we have in here i mean we have the low level concern which is in our case the database and the data access and yeah the application depends on this so it violates it right the i would say in this particular case the we rely on the i would say more like implementation detail rather than the abstraction and of course it's like someone could say okay direct but that's kind of because within my data access layer i can create nice abstractions and let's say i will create the implementation which will be internal but i will will only expose the capabilities of this class via the public interface so i will have nice abstraction which you can inject you can use it for the tests etc and that's true and i totally agree the issue that i have personally is if you think about let's say data access layer and let's just assume that you are using entity framework so probably you will have the dependency to entity framework in your data access layer which means that even though you have nice abstractions created and you encapsulate that let's say db context in theory there is nothing that could stop me from using the entity framework db context directly in my application layer and let let's say creating my own db context in there and using it as some sort of shortcut for accessing the data and that's because i have indirect reference from the application layer to entity framework core right because to the entity framework in general or to any other orm applications is dl dal sees let's say orm so i have indirect reference so there could be a situation in which you as a developer you know you've got a deadline or something and you say okay you know screw it uh the abstractions provided by the other guys are just too limited for me and i need to look into some few different tables and do the quite complex projection screw it i will just do row sql and i will just write this into my application layer and i will create one ultimate projection which will be returned further to the presentation layer and there's nothing that you can do about it because okay you used your developer skills to hide this behind the abstraction but from the technical point of view and the way you structure it by the concepts you basically broke the vip so this means that even that you that you tried your best i can still use ef directly without your abstractions and that's the that's the issue with this uh with this particular approach all right and i would like to summarize this section by reading the definition from eric evans ddd book so this famous blue book of the domain driven design if you haven't read it yet i mean i'm not quite sure what you're actually doing with your life you should definitely go and read it probably more than once because yeah i found it i found that every single iteration gives you i would say a few details more that are hidden within this uh within this book so great source of knowledge about understanding the domain and how we can actually model it and put into our application so in fact something for which we are paid right we are not paid and that's as i mentioned to me it's kind of kind of funny because on the one side i really get the fact that we as a developers are really into the you know cutting-edge technologies and frameworks libraries because it's kind of fascinating but at the end of the day we unless we have very specific job yeah we're paid for delivering the business value and i think that sometimes we would basically forget about it uh anyway the eric evans book contains as you probably expect the glossary for those of you who are as lazy as i am and yeah and in this glossary you have the definition for the layered architecture so it says um layout architecture a technique for separating the concerns of a software system so far this actually is fine and delayed architecture fulfills it right we have the each of the layer has its own responsibility so so far yeah we have different concerns spread into the layers however the continuation is isolating a domain layer among the other things and that's where clean architecture comes into play personally i like to think about clean architecture as some sort of layered architecture than right and the reason for that is very simple comparing to what we've discussed so far this approach is domain-centric it's not data centric so it favors domain over technicality and you will see this immediately once we'll jump into the code the domain will be the very first thing that we'll implement and further once we'll move on with the implementation at some point i would say that at the very end of this uh of this course you will see more technical stuff related let's say to database logging cross-cutting concerns in general so this is what i like you know today as a software engineer who's aware of the fact that yeah we need we need to care about the business and i'm really into the domain-driven design especially i really like this approach it's not perfect it's not ideal but we'll discuss this further and i would definitely not use it in every single scenario but it's it has quite a lot of advantages over typical layered architecture so without further ado let's just briefly discuss each of those layers and yeah we could finally jump into the code because that's gonna be quite a long introduction so let's start with the most important core most important layer which would be the core domain and one more quite important thing is that as in any late architecture approach we have the dependencies that goes inwards which means that in this particular case we have the presentation that sees the infrastructure infrastructures is the application application refers to domain it's not the other way around everything goes inwards so the domain as you can see has no dependencies and that's beauty of this approach this means that domain will not have any io operations ideally and if we think about it that's gonna make our domain pure in many cases and what i mean is that there will be quite a lot of pure functions within our domain if you're not familiar with the functional programming the pure function basically is the function which fulfills two conditions first for the same input gives the same output and it has no side effects so since we will not have any you know i o operations being involved in most cases this will be basically fulfilled of course assuming that there will be no randomness added it should be pretty much pure function and the whole purpose of this domain is to create nicely structured oop domain models which means that there will be no getters and setters which are public will have nice encapsulation within the objects each object will will have its uh will need to keep the uh that we will need to take care about its internal state about the validation of invariants within it and it's pretty funny because i mean we are taught about this on on a university or you know some online courses when we start learning programming but yet at some point we forget about it and we just follow blindly with this convention that yeah that the my model will have getters and setters no methods and yeah i will i will handle this somewhere else in the service now we in here in the domain will have object-oriented programming as it should be and besides we'll also have yeah this is a good place to incorporate the domain-driven design which i will not cover deeply and i will discuss it later but yeah of course if you if you have uh domain driven design already yeah this will be the place in which the tactical building blocks could be put so you know aggregates entities value objects repositories factories policies everything could be put into our domain because in many cases this will be just some sort of class that will orchestrate on the domain level something i will construct the aggregate and there is no i o needed for this so that's pretty much it when it comes to the domain will have few different things in there we'll have the exceptions we'll cover this why we have exceptions on the domain and what are they used for once we'll actually jump into the into the the code it doesn't make sense to actually uh discuss such such details now uh we'll also have the repositories mentioned uh but only the interfaces so the contracts which will which will tell us what i am capable of doing with my entity and domain events which will be also partially covered in here you will see how we can make the usage of them and that will be pretty much that will be pretty much it uh the key thing that you need to understand is that yeah in here we'll have pure c-sharp in our case that will be pure c-sharp class library with no dependencies so we can focus on creating the objects and behaviors between them and one more thing actually as an implication of having quite a lot of pure functions is the fact that the stability of this core layer will be quite high i mean there will it will be it should be at least very easy to test the core layer because there will be no dependencies external there's no need for using any test doubles like stops you know mocks it's it doesn't need to be very complicated in in many cases you'll see that yeah testing the core is just straightforward so in case in terms of unit testing that's quite a lot of advantages already moving up we'll have the application and the application is pretty much the same has its same same responsibility just like in the layout architecture so the idea is that we need to orchestrate our domain at some point and yeah this is the place in which we'll have the process logic rather than domain logic and in here we'll also incorporate the cqrs we'll also discuss it later what is actually cqrs and how this may be handy for us and [Music] yeah this will be pretty much it when it comes to application just an orchestration of our domain and let me just check whether i don't miss anything yeah i think that's that's it of course one thing that i need to admit there might be situation in which of course the application needs something more technical and of course the application itself will be will have this ability to create once again some sort of abstraction like the interface which could be implemented in the infrastructure layer and used within our application application layer with any abstraction leaks so once again we follow this is dependency inversion principle and yeah if application needs something more technical it needs to define the proper abstraction and this abstraction will be implemented by the infrastructure and simple as that and this will prevent us from any some sort of obstruction leaks just like we could have in the layered architecture then we have the infrastructure and infrastructure is all about the technicalities all the technical concerns the cross-cutting concerns so you know data access layer some sort of you know logging monitoring metrics anything which is technical will be within our infrastructure layer and yeah because the infrastructure layer will have direct reference to application and indirect reference to domain it can implement the repositories contract and let's say implement this on top of relational database or nosql database and as and all the same goes for the application if application defined any contract that needs to be fulfilled the application the infrastructure can basically grab it and implement on our on its site and there will be no abstraction link and the very last layer is presentation layer so in our case since we're going to implement this on top of asp.net core this will be once again web api and yeah this could be actually anything else this could be cli wpf xamarin actually we could have more than one entry point to our application we could create the rest api uh just like we've got we are going to do but maybe for the developers purposes because we don't like to you know run the postman or any other rest client for for our application maybe for us it would be easier to create alternative entry to our system and create very simple console application which would call let's say application layer or something it's it's pretty much all up to us so i know that at this point this might seem kind of i would say similar right it's quite similar comparing two to layered architecture um because it's just okay this is just a matter of arranging this slightly different yeah but this is yet still layer architecture but done in a way that eric evans actually described so hopefully you'll find it useful and hopefully you will see the advantages and yeah i think that at this point there are only two things left so um we should first discuss some sort of uh as my script says prerequis pre-war pre-rack so few prerequisites um first the other will have rather simple domain and i know that at some point you know it won't be the to-do list but close um and i know that you know some people down in comments may say okay but you know this is rather simple and uh you should create something you know more more robust more production ready or something like you know software for managing the rockets that are going into into the moon or something yeah i know i know that that would be ideal but i think that there are some sort of trade out trade-offs when it comes to recording such a course because on the one hand i would really like to go into some sort of deep domain but first it might not be the case of in the purpose of this video and would probably this whole video would take us way much time that it should and and then we'll also because we'll have rich domain will probably would like to incorporate the domain driven design which i really would like to like not to do and the reason for that is actually um number two on my list which is that yeah in general in the whole application there will be no too much domain-driven design when it comes to tactical domain driven design the reason is very simple i want to save it for another series of videos dedicated to domain driven inside to the domain driven design itself both strategic and tactical and that's also the reason why we don't have the rich domain [Music] some simplifications have been made and that's also because yeah at some point i don't think it makes sense to [Music] follow the principles just to follow them for its own sake if something could be done simpler i i wanted to go for it once again not to make this whole course too long which is ridiculous because i think that the introduction is already like one hour ago sorry one hour long um and the last one is that this is the most important stuff don't take this whole course and the code that you're going to see as some sort of state of the art the only valid solution no it's not this is how how i understand the clean architecture how i would implement this probably peter as well because yeah we're kind of close when it comes to the implementation so yeah we will discuss such a thing so peter would probably agree with most of my arguments when it comes to particular parts of the system but there are many developers on the world and probably maybe you will not agree with fully with with what you're going to see and that's totally fine i mean at the end of the day if something works or maybe you think that i'm over engineering something yeah if if this will work for you yeah go for simpler solution i mean i don't i don't see i used to do i used to be very pro uh very you know into the principles i now i'm more pragmatic if you'll see something that could be simplified you can write it down in the comments and that's that's fine maybe this will be helpful for for me personally but also for the others so don't hesitate to share it if you have any different you know different opinions and yeah i think that's yeah that's pretty much it so the last thing i promise let's discuss the application that we're going to to um create so i thought about it and yeah my very first thought was actually to-do list because it's rather simple but the issue with it is that there is not much domain so i added a little twist we're going to implement yet simple but maybe more fun application which is going to be a packing list so i i assume that you're traveling once a while and there's always the same [Music] issue at least i have the same issue is that i have my parking place that i'm doing manually i'm packing my my stuff to the back and at some point i'm deleting the list i don't care anymore and once new travel comes i need to create this from scratch so the idea about this whole application is that it will accept some sort of input and this input will be like the gender location that you're traveling to um for how long for how many days you're actually going to to stay etc and based on that input it will generate you the proposal right so your packing list what you should actually bring with you and yeah there will be slightly i would say that at the very first glance it doesn't seems very exciting but on the domain level i wouldn't say it's that simple like you may expect so the i would say basic use case would be this packing list generation of course simplified because you'll see that it's not it's not that simple uh and basic management like you know adding more stuff to the list removing it marking as uh checking this as already packed etc so this will be pretty much the scope of the project we'll call it packet and because and that's because you know pack it it also could be pronounced as ip which is not funny at all but yeah didn't have a better name so let me just check but i think that we are ready to go after yeah i think like an hour so i'm not quite sure whether anyone will will get into this point if you i can actually leave a comment that you actually were going through all of those fascinating theory and now let's jump into the code and see the clean architecture in in action all right so as you can see i jumped into my ide which in my case will be the rider and i've already created solution with as you can see six projects uh four of them are quite known to you already i also added two called shirt and so we have shirt and shirt abstractions the whole idea is that yeah maybe we'll have some piece of code that yeah i would like to avoid uh putting into each of those uh layers because maybe this could be like some sort of interface which will be shared all across our application and yeah i would like to avoid the situation in which we put this into those layers so this could go to shirt maybe eventually this will got extracted into some sort of nugget package who knows it's not required for our clean architecture but i'll just uh decided to add it and eventually we will maybe use it at some point so we have four i would say layers which are most important for us for now so we have the domain and as you can see this is just a simple class library project which is based on dotnet five since by the time i'm recording this video dotnet six is not released yet so i will just stick to dot net 5 and as you can see for now it has no dependencies just like we've discussed during the theory section then we have the application and application has direct reference to our domain project moving further we've got the infrastructure which has the reference to our application and our presentation layer which in our case is just a web api asp.net core project actually will have the dependency to our infrastructure and of course implicitly it has access to all those three layers so application and domain infrastructure because it's just indirect indirect reference so this is how it looked like how it looks like for now and let's just start with the domain because as i mentioned that's the beauty of this whole approach that it's rather domain-centric and not not data centric so we can already start focusing on bringing some sort of business value and creating the whole domain rather than yeah thinking about more technical concerns so just to remind you we would like to have this model that would allow us to base on some sort of user input generate our packing list so for now we can assume that this input will contain like three types of data this will be a gender this will be also a localization or our destination so let's say that i'm traveling to orso poland and the reason i'm asking user about this information is that based on this i will call some sort of external service this could be just assumption for for now let's say some sort of weather api and this api will return me the information about the average temperature so i will let's say know that by the time i will be in warsaw the average temperature expected is let's say 10 degrees of celsius so it's not very i would say warm so maybe you should take some so some sort of warm clothes with you and based on gender we could of course decide whether you should take let's say bra or something i mean if you're a man we probably don't need a bra and probably you don't need any skirts or something and based on the third parameter which will be the travel days so we can decide whether you should how many let's say t-shirts you need to take or trousers or socks or your underwear in general so those three parameters will be our input and yeah based on this will generate the proposal for the packing list of our user so let's start with defining our packing list object and yeah i wanted to as i mentioned i want to avoid as much domain driven design as i want but already i need to create first directory and i need to call it somehow so i will call this entities and now entities are not the entities that you might you know refer to entity framework it will be rather the ddd entity so i think it's fair to just give you a brief explanation what actually is an entity so in terms of ddd the entity is just an object with the identity so for now to simplify it we can assume that basically there will be some sort of id property or field within it and of course you could think about this as some sort of you know technical identifier like good or you know long or integer whatever but in fact in many cases there could be um some sort of natural key natural identity that you could found within your object so i will give you a very simple example if you think about let's say customer within your application of course you could generate a guide and this will be unique within the whole system and you're safe to go but if you think about the customer maybe there's something more i would say human readable for you some sort of more natural candidate and that could be let's say the email address in many cases the system that you're building will have this assumption that yeah just one email can go to one customer and it needs to be unique within the whole system so this could be some sort of natural identity for my identity for my entity which in this case this entity would be a customer object and that's pretty much all you need to know for now at least when it comes to entities and entities can be mutable and of course since i just want to remind you once again within the domain itself we want to do the proper oop so will not create anemic classes we'll just try to follow the object-oriented programming and encapsulate this object nicely so all entities within our domain will yeah we'll just try to validate themselves and yeah keep the keep their their internal state just valid for the whole for the whole life cycle of their existence so i would start with the entities and the very first entity i will add will be the packing list so packing list is our first and i think last entity that we are going to create so inside i will just need few properties so in this example of course i could speaking about the identity i could think about some sort of natural key maybe like the name of this packing list but on the other hand when we think about the functionality does this really bother us that you know user will create different packing lists with the same name probably not so i wouldn't say it's a good candidate and yeah since the domain itself is very shallow there is not much that we can do about it so for now even though i said that in many cases there is a natural key let's just assume that for now we don't have any and i will just create the public [Music] property with good as some sort of identifier and so we'll have the packing place with guit id and of course in this case i would like to have rather private setter because yeah i don't want to have it public otherwise there will be no encapsulation right okay let's move further so next we'll have let's just think about what we actually need within our packing list so probably our packing list will need some sort of name right so i will just create the public string name so just like so we'll have the name and this name will be of course used for some sort of identification but on like more human human level so i will not distinguish which list is let's say for warsaw which is for paris based on the guide because that will be tough it's rather the name that will help me to to know which list i would like to i would like to modify and interact with and yeah this actually already is some sort of very base entity that we could come up with of course maybe on the dui would also like to display the destination because the name may not contain this information so i think that the localization or the destination could be also very good some sort of information that could be used for the for displaying this information so i will add new string for now which could be localization so this will be get private set all right and i'll just change it to this and yeah let's just reflect on what we've done so far so we've got three properties on our packing list so this will be for sure used somewhere the identifier is our identity the name will help us to differentiate different lists on the ui and localization maybe could be also handy so i will know that yeah let's say packing list called my awesome list actually is reflects to my trip to warzone to paris however we can already see one issue when it comes to object-oriented programming it itself the issue i have personally with this approach is that even though my setters in here are private they get ourselves to your public right this is the public property with just a private setter so of course yeah i'm protected so the packing place will be responsible for setting values on both name and localization and the id itself but on the other hand there is once again nothing that could stop me from creating a logic built on let's say those two fields to two properties right so somewhere let's say on the application lev uh application level someone could basically create some sort of nasty weird logic that would say that okay if the name is x and localization is y then do z why i don't know why but maybe someone would like to do such a weird thing and i would like to keep all the domain logic within my domain because the application is reserved for the process logic not the domain logic and if someone is building the yeah weird processes on top of my properties yeah maybe that's the sign of not very good design so i would rather do the following i will leave the identifier public because i'll probably need it for you know getting let's say from my from my secret place i'm not want to say that from the database because this doesn't necessarily needs to go into the database directly but we'll cover this lately uh but i will yeah the identifier since this is the entity and entity is all about the the identity yeah i can leave it public however maybe the name and localization is some sort of implementation detail that i would like to hide from the outside of the world so i would rather turn this into private fields so instead of having this as a properties i would rather go for the private fields now keep in mind that this will actually have a huge impact on our further implementation why because yeah once we had the public properties we could easily let's say later use it for maybe orm or some other db driver to create the predicates and you know to create a filtering base all those properties and now since this is private i no longer have an access to that so creating any sort of searching on let's say rm level will be significantly harder it's not like impossible but it's just way harder so just keep in mind that this will have its cost but i think that at the end of the day since we are more favoring the domain over the technicality it still pays off all right so this is the first thing that uh first issue that i've got with the previous design the second thing is kinda it's kind of this i mean the we've got the name which is the string we've got the string that represents localization and i don't really like this approach because once we'll actually introduce the constructor for this so we have the constructor and yeah we could actually even think about creating this as an internal constructor because maybe i would like to only allow creating this public list via some sort of factory i don't want to anyone to call this this constructor directly so yeah i could park past the identifier for my for my constructor i will also accept this string name and i will also do the same for the localization and yeah of course i could assign this right so i'll do id the name equals name localization equals localization so if you have ever read about you know some sort of cold smells you'd probably like immediately you could discover what's what's going on here this one is quite well known i would say a cold smell called primitive obsession and yeah the primitive obsession basically occurs when you have the method or like in this particular example you have a constructor which accepts a lot of primitive types now you could say okay derek but i mean seriously what's what's wrong with that i mean the string name what is wrong with this i mean string name yeah name will be probably text so yeah in c sharp we have hello one data type that can handle the text which is the string and the localization will be exactly the same case right well yeah not exactly i mean of course the data types are the built-in data types are just perfectly fine and i'm not saying that we should stop using them however data type as the name says is for the data and not necessarily for the behavior so if you have any sort of validation and once again we want to have the object self-validated like you know name cannot be empty of course the if if the string name is null i could create a logic somewhere in here right like in the constructor maybe i will create the some sort of validation inside my packing place object or even further i could i could validate this on the application level or even on the api level that's that's totally fine however yeah the issue that i have with this approach is that yeah we're talking about self-validation and object-oriented programming yet still this validation rule that the name cannot be empty links to the application or even further to the presentation layer because we couldn't done this properly on the domain level and yeah we just need to make sure that every single time we're using the name we'll do this proper validation and of course this valid also single responsibility principle because if we will have a situation which like i'm using the name in many places every single time i'm using this name i need to make sure that yeah that this is not empty so i will either delegate to this logic to different object like to packing clays to validate this or i will do this in more i would say domain oriented way more object-oriented programming way in which i will create a separate object which will encapsulate this value and it will be this object's responsibility to self-validate whether this actually is a correct value or not and this is where another i would say tactical domain driven design building block comes into play and this is called the value object so the value object comparing to the entity will not have the identity itself so i could not compare two objects by their identity by their identity so in our case just ids and says okay this is the same object the value object is compared based on its properties since i don't have the identity i need to compare the two objects based on their properties and if they are the same i assume that this object is just the same object and i know that this might sound kind of weird so i will just do my best to give you some sort of um maybe analogy in the real world so let's just think about the following scenario you're going to [Music] let's say some sort of store and you would like to buy a computer some sort of laptop so you know already that this will be let's say apple macbook pro with m1 max processor and 32 gigs of ram and one terabyte of storage so this is the exact spec and you all also know that this is gonna be the space gray color now you're coming to apple store and you're telling the spec and the customer is telling you okay yeah we've got this on stock we've got like we've got three laptops on stock would you like one and for you it's like yes i would like one but does it really matter whether you know the the salesman will give you the first second on the third probably not because each of them has the exactly same spec and it doesn't really matter to you whether which one you get it's just the matter of the spec so for you this macbook is nothing more but at this point the value object and for you all those three laptops are basically equal now the funny thing about domain-driven design and you know entities in the valley objects is that this not necessarily refers to every single context within your application so in your from your perspective in your context of you as a customer this macbook is just the value object however in different context this macbook could be now an entity so let's think about the following you're using your macbook and suddenly it's it just breaks for some reason so you're going to apple service calling them you're bringing the laptop and yeah now you now you wait for the for the service to be finished so for the service guy they can just treat your laptop as some sort of value object with the and just compare the laptops based on spec because once i give you my my macbook i assume that i will get my laptop with my data my identity you know apple id on that and not the others so now for the for the service guy this laptop is rather an identity which probably will be this identity will be based on the serial number so based on this i will know that okay this particular laptop with this serial number belongs to this owner so i need to make sure that once i will repair it the same instance of laptop gets back to its owner and not to the other random guy who owns the same spec so hopefully this you will get the idea about what's the difference between the value object and the and the entity so in our case when you think about the name which cannot be empty because let's say that this will be some sort of assumption and localization which could be actually more specific because for now the we keep this localization the string but maybe i would like to be more precise so what city and what country i'm actually traveling to yeah now i could create object that would encapsulate those values and this object would be responsible for self-validation and also i could basically you know um check whether two value objects are equal based on their on the properties not on the not on the you know some sort of word assumptions so i'll just create one more directory called value objects and yeah let's start maybe with this with this name so i'll create an object called packing list name so you know the cool thing about now creating the valley objects is that i would say that it used to be more painful in terms of the implementation or maybe that was maybe not the painful but it was less pretty because yeah if i would like to let's say create a packing list name class i would probably have the some sort of value that i would encapsulate so in this case this could be called value or the uh or the name i will just stick to this convention where i will just encapsulate a value but yeah it doesn't really matter and then one thing though which is kind of important is that value objects are by nature immutable so if you need any change yeah you just need to create another value object so this allows me also to you know create to share the value object with other with other let's say parts of my system without fear that yeah eventually if i will modify this by reference yeah you'll have some sort of weird issues uh with data inconsistency so this is the very simple assumption the value object will be basically immutable now if you would like you know let's say past times before c-sharp 9 occurred if you'd like to create this equatability you would like to implement i equitable of t when the t will be the packing list name parameter and this will generate you based on the value string those those equals and hash code methods and now i would say it's not pretty um especially if you only want to validate whether this is not null or empty i would say it's it's it's a good good deal fortunately since c sharp 9 we have the records so now if i will change this packing list name to record you could already see that this i equitable of t is now grayed out and the reason for that is that the record by by themselves by their nature will implicitly implement this interface so there's no need to now explicitly implement this interface and i can just remove it so that's good now let's create a constructor for our packing list name and inside here i could validate whether this particular string dot is null or white space value whether this is actually empty if it's then i would like to throw an exception so probably exception and of course i could do something like invalid operation exception or like invalid argument exception etc so the exceptions that are already built in my programming language and that would be totally fine however i found it useful that it's it's rather better to create some sort of um custom exception types and that's because of few reasons i would say that it's way easier to test and it's more explicit when you can create the tests on top of custom exception types because yeah invalid operation exception could be anything while let's say packing list empty packing list name exception is very specific so i don't even in many cases don't need the message to know what's going on actually it's the name which will be very explicit and will explicitly tell me that okay i i didn't pass the proper value for my packing class name so this is the first thing the second one is that you know the invalid operation exception and any single exception built in the language is just i would say commonly thrown from different types of frameworks because they are yeah if they don't implement its own exception type then they probably use the the one delivered by the language so if i will got like invite operation exception now i wouldn't be certainly sure whether this comes from my domain or maybe from the application or whether this comes from my infrastructure while once i will create and introduce my own exception types it will be rather straightforward so this one will require another directory called exceptions and before we actually move further i would like to create my own base type for exceptions and the reason is very simple it will be i would say it's uh way easier later eventually once we'll deal with the error handling to filter everything that comes from let's say domain or from the application and was basically our custom exception type rather than anything else so just for this ease i would like to create my own base type for for the exception so this is where our shirt package comes to play of course i could put it into our domain but to me it's like this is some sort of concern that i would like to share all across my application so maybe it's better to to put it into the let's say the shirt obstructions i i know that this could be for some maybe in sort of overwhelming but yeah you can just get rid of those shared packages if you don't like them it's all pretty much all up to you so inside my shirt abstractions let me just create a directory called exceptions and here i'll create my base type which i'll just call packet exception so just to know that this actually is my own custom type and i will just mark it as abstract so just to make sure that no one will create this type of exception and this will be deriving from exception and i can create the protected constructor which will be packet exception this will accept string message okay and i will just pass it to my base type and that will be pretty much it when it comes to packet exception itself of course i could think about some sort of error codes like in here like maybe i could add some more fields all the properties depending on my need but yeah i'll just stick to this particular uh implementation just for now so now i can back to my domain and create my first custom exception type which in our case will be empty packing list name exception all right so i've got my class and i can derive from my packet exception and of course this is the point in which i don't see my base type because the domain itself as you can remember doesn't have any references so okay i was telling about the fact that this is the beauty of this clean architecture that yeah the domain is pure and yeah we don't have any external dependencies yet still to make it work i need to add the reference to my shared abstractions and that's actually the reason why i the distinguished both shirt and shared obstructions to me the abstraction itself if this is actually an abstraction and the abstraction itself will does does not contain any once again i o uh the assemblies that could bring me some sort of i operation then it's fine i mean it's just the extraction of some types to to some external package and to me that's still clean enough of course if you don't like it and you want to really have no dependencies within the domain then yeah by naturally you need to bring it to your domain but for me it's just some sort of natural continuation so now my packet exception is visible so i can implement this yeah and i will implement this in maybe a slightly different way i'll just write that in here um backing list name it's empty yep and that could be maybe cannot be empty i'll be more precise okay all right so we have our first exception which i can throw in here so for now i would say that's pretty much pretty much it the only i would say improvement that we could do here is adding the implicit conversion from string to packing list uh name because maybe yeah we'll probably not use the value objects on the transportation layer that will come to our web api will rather stick to primitives but yet we would like to have this ability to to turn this into a valley object so i could improve it a little bit by doing public static implicit operator string so this will be the conversion from value object to string and that will be the packing place name which is name okay and that will be just name dot value so this is the conversion from value object to string and the second one would be conversion from string to our value object and that will be just new and we can implicitly type it as this and now yeah i would say that at this point it's pretty much legit this is something that i will be really proud of and i can already change the implementation slightly in here so now my entity will contain parking place value object rather than this primitive so this looks already way better and the same of course will go for the uh for the for the localization so yeah we can just create it right on uh let me just add new one i will just call it localization so localization actually we could think about this value object uh this will be of course once again the record maybe i would like to be more precise so not only i will just uh have a city because yeah there may be the same city name within within the country or something else so i would just would like to distinguish city and the country of course probably there should be additional postal code and something else because there might be a situation in which we have like city multiple cities with the same name within one country um i think it's still possible but i don't want to waste my time on you know creating the logic for the for for the country and for the localization in general um yeah so for now uh i think that this will basically do its job of course we could do also the conversion from let's say string to value object and we could do the assumption that yeah once we'll sort this to string we'll have the city and let's say commas operator or something else and then country just to store it in one string maybe in database we would like to store it as one string we'll see um so yeah let's just maybe add it i'll create public maybe static factory method very simple one that will accept those two so let's say that i will have the value that comes and i have very simple assumption that yeah this will be split so split localization equals value dot split let's say yeah and that will split it and return your localization and this will be first so this will be our city and split localization last yeah so this will be our conversion let's say from string to value object and from value object to string we just need to overwrite the tostring method and this to string will be just let's say interpolated string and that will be city and then country so once again some sort of conversion conversion from from string to value object and from value object to string okay we can now get back to our entity change the implementation once again and it looks way better okay now when we move further with all of that we'll probably need some sort of items that we'll insert into our parking list that's something that yeah at some point would be cool to add and of course this is once again assumption whether we would like to treat our packing item as some sort of ide sorry entity or valley object at first glance i think that yeah having this as some sort of entity could be cool yeah i could make this immutable and i will have the internal id of this object however we could do this assumption that maybe i i don't like to have the duplicates within my list because if i if let's say list that was generated by my application gave me the proposal of let's say sucks and i will add this once again by mistake i will take too much socks and i could have an issue with the luggage weight on the airport or something so i would like to avoid the situation which i have the duplicates so i could create um i would have this assumption that yeah the the packing item will be basically the valley object with no identity and yeah once i will like to edit this i will just you know need to throw it away create new one and i think that this will work just fine and this is just i would say matter of the implementation detail whether i would like to as a let's say domain expert whether we would like to keep this as an entity or to as a value object for me this will work as a value object i think just fine so i'll just call it packing item all right so the packing item basically will contain three pieces of information i'll just change this to record of course i will need to keep the name so let's say trousers or t-shirts or something else probably the quantity will be also appreciated so i will know that let's say i need to take four t-shirts for my journey oh geez that was quite bad okay quantity and yeah as you can see i'll use the inside integer probably this should be outside short because maybe i will not take like one million pairs of socks but who knows and uh i will also create a very simple flag called ace packed so as the name says yeah this will be either the mark for me whether i already packed this or not so let's create the constructor okay so the constructor gets me those three values and of course maybe i would like to create some sort of validation once again so for me the only thing that needs to be validated actually that yeah this actually is just uh this could be just name of course the quantity probably should not be you know should not be zero but yeah let's just stick to name i don't want to you know cover every single case uh let's just once again assume that the name for the packing item cannot be cannot be um empty because it would make no sense this would not appear on my on my ui and properly so i need to make sure that this actually is yeah it's not null so let's just start once again with the exception i will call this this time empty packing list item name exception i've got a type once again okay and i will derive from packet exception once again i think i don't need any sort of message in here i'll just write information that packing item cannot actually name cannot be empty all right let's just jump back to our value object which is this one and let's create our logic so is null or white space name throw new empty packing list exception okay and this does not require any addition parameters so that will be probably it when it comes to our packing item value object so now once we'll get back to entity you can create a list of those items because i would say that's the whole purpose of this object to have the list of those objects so let's do a private read-only and i will just call this link this for now so this will be linked is because maybe i would like to yeah put something in the middle and just you know keep the same order so if i'm deleting something from my value object um i cannot modify it so i need to remove it completely and replace with the completely new value object so i would like to avoid the situation in which someone deletes let's say third value object and once you add a new one which is let's say correct value it appears on the very bottom of the list because you are using just regular lists so linked list would be better in this particular approach and this is some sort of consequence design consequence of this decision that yeah the packing item will be rather an immutable value object rather than the the entity so i will have the packing item collection here called items and i'll just initialize it in here and i can also add this already to our constructor so packing item now is the part of our constructor items yeah and i think that now once we have the identifier we have the name we have the localization and the items we're pretty much good to go of course at some point maybe there will be a need for let's say creating the packing list without our items or something else but so eventually we may we'll maybe add something more when it comes to constructors to our entity but for now we'll just leave it as this okay so we have our internal constructor so for now we have no option for creating this from the abstraction sorry from the application layer that's fine and it will be also good to add some sort of public methods which will allow us to add and you know remove those items from our collection because that's the purpose of this list so i will just create a couple methods which will just do this so first one will be public void at item and as you probably expect this will accept the packing item as my parameter so i'll just do public uh sorry package item item and yeah in this particular method i would like to do certain logic so first i would like to check whether this item already exists so let's say the item with this particular name already exists if it is i would like to throw an exception because for me as i mentioned i will want to avoid the duplicates within my list i want to make make sure that only uh one position uh is allowed and no duplicates are allowed because maybe after some sort of i do really care about the customer's luggage weight on the airport so the logic will be very simple i will just create a variable called already exists and i will check inside my items whether there's any item which is what's name so i dot i name equals my item dot name uh sorry item dot name all right so if this is true and i'm in trouble and i want to throw an exception so throw new and i need my custom exception so i'll call this packing item already exists exception right i have my exception let's just derive from our parking item sorry parking packet exception and in here i will accept maybe two parameters so first will be what is the name of the list that i try to modify and maybe what duplicate i wanted to put so i will have like item name and list name in here and the message will be maybe a new line let's just create an interpolated string in this case so packing list and then in here i will just do list name already defined item and it's called item name and of course if you like we could think about uh some sort of assigning this to maybe some sort of property so yeah i could do something like this maybe i will use this information this information somewhere else in my system for now we can just leave it as this so let me just jump back to my method and let's just throw this exception so in here once i have it i need to pass the name from of my list and of course the item.name and yeah if actually it doesn't exist within my list i can do just items dot add last and that's item which comes as a parameter now at this point i would like to discuss something because this might be kind of weird too some of you may think okay but derek you're doing kind of weird thing because every single time you're throwing an exception so every single time something happens you basically throw an exception and why is that why you have the methods that are void and they don't return any result and instead you just throw an exception so let's just discuss what are the possible ways of validating the internal staff of my object for now this will be an entity which eventually will turn that into then aggregate but yeah i just don't want to bother you with too much definitions at the very uh at this i would say stage of the of this uh video of course so let's just assume that yeah for now it's just an entity and i would like to keep be you know valid with the follow the object-oriented programming can validate my internal state so there are three possible strategies that you could apply to our object so first one will be of course returning some sort of boolean or if you would like to you know we already know the value object so we could think about some sort of result of t or maybe just result that could be returned from my method and the assumption is very simple i just if this happens i will just return new object which will have the information which has the information that yeah this particular addition to my list couldn't happen because we already have this this item with the same name inside so yeah based on this we can construct some sort of response to our client and return let's say 400 but request with the information that sorry but we couldn't process your your request the second option could be slightly different so there will be no result because maybe that's weird to us and we'll create a dedicated validators that yeah we'll just remove completely every logic in here and yeah we'll just add it and yeah the validator will check whether we have the duplicates and if this actually is a case then this validator will produce the response to the caller let's say to our some sort of you know ui application with the information that sorry but it's duplicate we cannot basically process your request and of course in this case that could be more tricky because we have this nice encapsulation so we could think about either i would say relaxed approach in which we would have the proper sorry public properties with private setters or we could think about some sort of you know uh some sort of reflection that would go through my object and check it but i wouldn't recommend doing this but nevertheless you know either you'll choose approach with returning the result of the with this deferred validation both of them have i would say yeah this thing that bothers me is this assumption that yeah you need to be certainly sure that someone on the higher level let's say on the application level we'll actually perform this and actually we'll check either result or we'll perform this validation using the validator object you need to be certainly sure that this will happen every single time i'm adding let's say item to my list because what happens if it doesn't you'll basically let you'll break your business rule your breaker invariant and yeah the business rule was clear you cannot have the duplicates within your list and since you forget about validating the results that comes either from method or or from the validator object you broke this rule and it just yeah you you have the inconsistent state within your database something that should not happen actually happened so i know that from the no performance wise the exceptions are not great i i mean there they're now i think better than it used to be but what i really like about the exceptions in terms of domain driven design and you know valid self-validating of the objects is that once i throw this exception i'm certainly sure by by the nature of this particular object that the execution is immediately suspended and i will not reach this line of course someone could say yeah but you know i could create the let's say on the application layer i could create a try catch and yeah eventually maybe and it's some sort of way i could prevent from the you know application to break and still persist it yeah but then you're an idiot i mean you're doing this on purpose and of course i could break any single rule by doing you know reflection and accessing the fields that are should not be accessed let's say from the other another assembly but if you're doing this on purpose then i mean i don't see any point of doing this uh with the previous approaches so with either returning the result or doing this performing this deferred validation yeah this could occur by mistake by the fact that yeah i didn't realize that this needs to be performed every single time and of course those two previous approaches also i would say partially break the srp right so it's like every single time i'm calling this ad item i need to in one transaction i need to perform the validation stage at some point and it leaks because i didn't stop it here it links further to my application or even further to my let's say presentation layer which would be the api in our case so yeah i think that at this point uh since i'm already discussing the self-validation and and protecting the the business rules i think that i could already discuss also the the concept of aggregate because eventually this entity so our packing list will turn into an aggregate and you can think about the aggregate in some sort of continuation of this object-oriented programming actually uh because yeah what i told you so far is that yeah if you have some sort of business rule that needs to be validated you are going to put this into into the object and the object will be responsible for self violating for checking and making sure that every single input that comes to it is correct and eventually you can change the internal state of your object and this applies both to entities and each of our value objects of course at some point there might be a different business rule that says okay you know you've got let's say two value object or even you know value object entity and there is a rule that if object a changes then you also need to change object b you know i i don't want you to specif let's say that once i will change the localization i also need to change the name of my packing list name it's it's completely ridiculous but let's say that there is a certain rule now the issue with this is that now this rule is outside of scope of my particular either entity or valley object and of course once again someone could say okay i will just create a sorry application service that will make sure that once let's say one object changes then the other also needs to be changed but yeah once again because you didn't have any proper encapsulation on the domain you need to do this on the application level and of course every single time one object changes in in our application you need to check whether the second also changed if not then you need to probably yeah inform the user that this is not allowed and of course we could go even further and once let's say new colleagues come and they are creating their own application services they might use the same let's the same rules right they need to follow the same rules so you need to make sure every single time that once they will use one object and they will change it they also need to change the other one so you're duplicating the logic that should be nicely encapsulated within your domain and yeah once again the same principle when it comes to objective programming is violated so now you're suffering so the aggregate is the representation of this i would say transaction within your within your i would say bounded context but yeah for now let's just say that within your application so if there is any some sort of invariance that needs to be atomic within the one transaction like if a changes then b also needs to be changed you can basically wrap this entities and value and and value objects into aggregate object and this aggregate basically will be object representation of your transaction boundary and it will be responsible for checking those invariants and eventually if if you're violating them if the aggregate basically can throw an exception informing you that sorry but you forgot to also change the object b because to change object a in our case it's we don't have such rules that would say that let's we didn't have such rules like if this changes this also needs to be changed but in terms of domain driven design and what we are going to introduce which will be the repositories we will have this assumption that packing list will be at the same time the entity and also aggregate so this will nicely encapsulate the let's say rules within within uh its internals so will basically some sort of transaction guard yeah but we'll not necessarily use it capabilities that much but once again i don't want to go into domain driven design that deeply i will probably cover this in the into the completely separated series yeah so i think that since we already know that this yeah that will have some sort of aggregate and this is just the explicit object that represents our transaction we could think about creating maybe the representation for it so you will already be familiar with the concept so let's just jump to our shirt and within the abstractions and we'll add directory called domain and i'll just create a class called aggregate root so yeah this will be just the representation for the simplicity simplicity cycle just assume that this will represent our aggregate so i'll have the abstract class aggregate root with the t when the t is just basically the type of identifier so we'll have this assumption that the aggregate itself will have few properties and this property will be identifier which will be just get let's say protected set okay and for now we can just assume that the only thing left is version okay and the first will be used might be used but not necessarily for something uh let's say checking on the database level uh or some other on some other level let's say using this for optimistic concurrency or something but for now let's just with no further explanation let's just leave it with those two with those two properties and the only thing left will be maybe method for incrementing this version so the assumption is very simple once you will modify anything within the aggregate you need to increment this version so this will be some sort of clear sign for to me that yeah there was some sort of change within my uh within my aggregate and maybe yeah this transaction needs to be performed to make sure that yeah we have new data in our database so i will do something uh very simple i'll create one more private bull version incremented field and the reason for field is is that i if i will do multiple changes i would like to bump this version only once and so i don't want to jump let's say from version one to version eight i would like to just increment this once and yeah have this very simple mechanism yeah that's pretty much it so now i can already do another i would say refactoring so there will be quite a lot of refactoring but i don't want to i want to naturally introduce some sort of concept and see how this code will evolve so i will now implement our aggregate route and our identifier would be the parameter now at this point someone could ask okay but you introduced these value objects for packing list name for the localization and yet still ones of the most important stuff which is the identity of my packing list is still kept in the in the primitive and that's actually a good point so as a continuation we'll move further with basically the packing list identifier so let's just jump into value objects and create packing list id and you already know the concept so i will just write it so we'll have to do it which will have the say the value this will be immutable you already know it will perform the some sort of logic so i want to make sure that maybe this guide is not empty because if it is then i basically i'm screwed so let's just throw what i want to throw of course you already know it this will be my custom exception type which will be empty packing place id exception all right we have it i'll just derive from packing and pack it exception which is this one i don't require any specific parameter i'll just pass the information that packing placed id cannot be empty okay i can get back to my value object and yeah i think that i should be good to go of course once again if you'd like we could maybe steal this implicit conversion so now we'll go to guide and do this this this and here we'll have id this this and this okay and it says that we have uh packing list identifier and that will be the good rather okay so now we're good to go so we can proceed with our refactoring now we can pass it in here we are good to go so now i think that once you actually know the concept of aggregate and the fact that this aggregate will now be responsible not only for um you know for keeping the identity because it's also an entity itself but it's also responsible for keeping the consistency within my transaction so not only every single data that comes into it needs to be needs to be valid so not only that every single fields needs to be valid but also the business rules between those objects within my aggregate needs to be fulfilled in order to to proceed further let's say on the application level and this is also explanation of why you need to throw in exceptions because the exception is the only mechanism at least to my knowledge which will prevent me immediately from further execution and at some point of course if you think about value objects yeah if you can return the value from the constructor let's say yeah you're uh your genius of course you could do the overcome like creating some sort of factory static factory map for this but that will generate more boilerplate from um from our implementation and yeah if the factory returns let's say packing list id then you would need some sort of out parameters that would give you a hint that maybe this is not uh success didn't succeed so i'm not the very uh a fan of it i'm just throwing exceptions and i don't care uh if this will be you know best from the performance uh performance wise or not now another question that might pop into your head right now is the following okay direct you've got the entity which is of course in this case already also the x the aggregate so this will be my guard of the consistency within the transaction cool you've got this messages sorry this public api which allows me to interact with my aggregate and you have these nice exceptions which are from so how the heck i'm let's say i want to create the unit test for it so how the heck i i know that this actually succeeded because of course yeah i could do this very simple assumption if i've got the exception then yeah then i will have this assumption that this actually succeeded but what happens if i've got something like this i forgot to put this yeah that's not i would say not easy because once we would have this as a public properties the word will be i would say way uh yeah the whole the whole issue would be way easier because the only thing i need to do is check whether packing clays dot let's say name is the equals to the one that i passed into my into my method while in this approach i have no access to my private field so i need to some sort of explicit information that this actually succeeded and to deal with that with this particular model and i mentioned that there will be few trade-offs with this approach and and the first of them is that we need to introduce another concept within our domain so this concept will be called the domain event and the general idea especially if you are aware of what the event actually is the domain event basically represents something important from the domain's perspective that already happened within our system so this is already this information informs us that something already happened we cannot we cannot undo this if something happened we can't undo this and basically the idea is very simple once we'll interact with our aggregate using our public api which will be this public methods the as a result will not only muted this internal state of our aggregate but we'll also produce this domain event and add this to internal list of domain events of our aggregate and thanks to this i could verify whether something already happened so this will be my input and my expected output of processing this particular method would be producing some sort of domain event and that's the whole idea kinda simplified uh when it comes to my when it comes to my domain events so let's do the following first i will add in my short abstractions one interface called i domain event so this will be nothing more but the marker interface just for the generic constraint purposes and now i can first start with i would say multiplying my aggregate route by adding the collection so my aggregate route will be responsible for keeping the collection of those events so let's do the following i'll add private read only okay private read only list with i domain events okay now we'll just do new and yeah because now i would like to also have some sort of public uh information about what domain events i actually produced within my aggregate i will also expose a public i innumerable property of course this will be innumerable of i domain event called events okay and we'll do events yep and last but not least we'll need a method within my it should be protected because i want to use it only within my aggregate so this will be method called alt event and we'll accept of course i domain event called event and we'll perform very simple logic so if we don't have any domain event and you know we haven't incremented my verse our version yet we'll just bump the version because this will be let's say this first change within our aggregate and i will change this to version incremented so by adding our domain event i will also like to you know implicitly bump increment my version by one but only for the first time and eventually i will do events dot add and then event oh sorry i need to change this underscore to add okay and i will also add one more misd okay i miss this one and i will also add maybe for some reason method for clearing events so the whole idea is that those domain events will only live without within the i would say one http request [Music] lifetime so yeah once i will actually persist this aggregate to my let's say database i basically once i will restore my aggregate the domain events are gone i don't need them of course i could persist them if i would like to and that would be some sort of partially some sort of basement for the from the maybe foundation for the event sourcing uh which i will not discuss in this course but for now we'll just assume that yeah we'll we we might need those domain events for maybe unit testing for validating or for performing maybe some other domain business logic within our domain layer but yeah once we'll actually persist this aggregate we forget about those those events we don't care anymore so the good news is the aggregate route will know uh yeah will will not grow anymore hopefully [Music] yeah that will be probably the final version of it and now we can get back to our packing list and somewhere in here once we actually add the the uh item to our items list we could call our add event method so let's just add another catalog within the domain will be called events and this event will i'll just call it something like packing item added so this class will basically yeah this could be actually anything that we would like i will just make it record because those events will be immutable so as a shortcut i think that it's it's quite handy to do the following so i will pass the packing list so packing placed and maybe packing item as well and of course i need to implement the i domain event marker interface so i can now safely use it within my add event method okay i'll pass this and the item and yeah we've finished first method where it comes to our aggregate so let's just quickly uh so let's just quickly uh extend this implementation so maybe there will be a need also for adding multiple items so there will be like items in which i will accept not one but like innumerable of packing items so will be items and the implementation is rather straightforward that will be foraged on items and i will call item and inside add item so in this case you can see that this will produce multiple packing item domain events but the version will be bumped only once so that was the whole purpose of this guard and checking whether this actually was previously incremented or not okay then of course at some point it would be cool to mark the particular item as packed because that's the whole point of of this let's say packing place i want to make sure that yeah i will just check it as something that i already have in my bag or my luggage so i will call it public void pack item and as a as a parameter i will just pass the name of this of this item of course some sort of okay and of course for the item name i don't have any value object but in this case it's not i would say it's not violating it's not like it's primitive obsession because yeah the the item name itself was the part of my valley object so the value object was responsible for checking whether this actually is now or not this will be only for the search purposes so it does not violates the it will not lead to an inconsistent state even if that will be null this will not violate the internal state of my aggregate so this is why i can pass this safely without any any fear so first thing of course i need to get this uh item somehow so let me just create maybe one one private this time private method i will call this get item who would expect okay and based on this okay i'll return the packing item so the item is basically items then i can use safely single or default because i've got this assumption that there will be no duplicates of course i need string item name so predicate is rather simple i dot i name equals item name now i can check so if this item is null then there's something weird that is going on so maybe i'll throw an exception and inform you about that weird thing so you're trying to pack item that you don't have of course from the uart's perspective this kinda this will rather be never called but maybe someone is you know messing up for api and trying to put the data that makes no sense so yeah this might be actually a good to to have this some sort of security null check so let's create another exception i'll call this packing packing item not found exception okay and once again package exception and i'll just accept the item name and i can actually assign this maybe to property and interpolated string which says packing item and item name was not found boom okay let's just refactor this okay to one liner all right we are getting closer i promise so i can use it item name and yeah if this is actually not the case we'll just return the item okay so now i can use this method in here so first thing will be calling our get item so get so get item and item name okay and now a very cool feature that comes with the records is the fact that i can create the copy of the record we've changed property using with operators so if you would see i could do something like packed item would be my item but with changed property and this property is is packed and i will set it to true so this is kind of cool and i'm not quite sure property without setter without setter it is actually set to needs to be set to init so that was pretty bad um if you don't know this the init basically means that this can be initialized either only from the constructor or from the object initializer so it's like immutable but gives you this flexibility to choose either you want to set it from the constructor or the object initializer it's still like immutable so now because i've got the init i can use my wiff and yeah that's very cool thing because other other primitives within this valley object will get basically copied and i don't need to explicitly yeah do this explicitly this assignment so now i'll do items dot find i want to find my item and i want to set the value to packed item so i will not change the order of my of my packing items and last but not least very crucial for our design we want to add the domain event so i'll just add another class called packing list sorry parking item packed i know kind kind of stupid name but yeah this is how it is and i think that we can also copy the payload of this message okay all right and let's just use it okay here yeah packing this item and i'll pass this and item and the very last last one which will be removed item and this remove item will once again accept string item name and the idea is simple once again we'll call our get item internally and items dot remove item and once again at event maybe packing item removed so packing item removed okay and this will be once again the record and i think that once again we can use this payload just to spit speed it up a little bit okay oh geez once again pale okay this item i believe or not we are almost done when it comes to our when it comes to our implementation of our aggregate so we have nice proper sorry private fields which are wrapped into value objects we have only the public api of our aggregate which allows us to modify its internal state but this state is validated by the aggregate itself and yeah if some rule is violated we basically throw an exception and we shut down the whole execution immediately without relying on any third party component or or you know or the upper layer which is in this case application so we prevent this eventual validation leakage further which i believe it's it's a good it's a good thing of course at some point you might also ask okay but whether some things like whether something is empty or not couldn't be validated at the very first round let's say on the api level using let's say data annotation yeah of course if if you have the input like this you could dedic you know distinguish what is the data validation what's the domain validation but once again since this is rather simple app i i need to make some sort of trade-offs so in this i in this particular example i only have this checks on on the strings which need to be required required and this is why i have this okay i think that this could be pretty much uh pretty much it and one more thing that maybe we could improve is the following because now the only piece that we miss within our domain is of course the way to create this because this is the whole purpose of this internal constructor we don't want to want to have the factory that will actually construct this packing list um yeah but maybe would like to avoid this as a parameter that will be called by our factory because if we'll pass these items in here we would probably do something like items.items and there might be a situation in which we'll have this duplicate because we'll not directly call this method right this logic will not be called so i will just assume that the input that comes to my constructor is valid and i will just blindly assume that yeah okay this is fine in this case which actually should be also refactored to this in this case it's just fine to assign this because those objects itself will internally within their constructors validates whether the values are correct or not while this is some sort of business rule that is responsive responsible it's the aggregates responsibility so i will do i promise the last change to this code i will create another constructor which will be also internal and this constructor will accept only three parameters so this parameter will be the identifier name and localization and prevent this i can safely assign this one okay and this we'll see uh but probably should not be used for now i can actually safely remove it because yeah there are two ways to approach it first is that this could basically call my base and this base to the following thing i will just pass the id name and the localization i can now remove it uh sorry not based but this okay so i'm calling this particular constructor and those three fields are getting assigned while the items i would rather to do something like add items and pass the items however keep in mind that eventually probably this constructor i mean it could be called by our rm so once we are actually getting the data from the database it could but not necessarily uh yeah we could uh get this object from our database which means that every single time would get the object from the database would perform this this validation and it's not something that i probably would like to have because yeah i assume that everything which is within my database is consistent and if it's not then it's already too late so it makes no sense to validate something um once i'll get the data from the database so for now i'll just remove this completely i will stick to those three so my assumption is very simple factory which will be responsible for creating this packing list will just put those free both properties and property and fields into my aggregate but further adding items need to be done through through this method for this add item method okay and if we'll need the items if we want to do this items and do this in safe way then it needs to be private because yeah other way we cannot be sure that these items that come externally are actually valid so yeah i think that maybe i will just leave it for the uh just for now we'll see whether we'll actually use it or not probably i will delete it at the very end of this course because i don't think we're gonna need this overload it it will be rather this one that we're going to use and the rrm itself will use the parameter less constructor which we'll discuss later okay so let's just jump into the factory and let's just discuss how we're going to tackle this because the according you know you probably know the factory pattern and in the domain driven design basically yeah the the whole purpose of factory is just the same so we would like to delegate we'd like to have the place in the code which will be responsible for for validating uh sorry not for not for validating but for creating our our aggregate so in our case that will be the packing list that needs to be created and constructed somehow so we don't know we don't want to have um any knowledge of how this actually gets created we'd want to delegate this to to the factory method that will do its job so within our domain i will create the directory called factories and within this factories let's just add first interface so i'll call this i packing list factory okay and i can already create the maybe implementation so create derived type there will be the class i will just remove it to i'll just move it to cs file okay i've got it so the factory method will just give me one particular um one particular method it could be actually we could think about this factory like in two ways so i could either allowed myself to create an empty packing list and eventually call at items or i could create the parking list already with predefined items and generated by my domain so we could distinguish those two scenarios so first will give me packing list based on oh maybe call this create so based on three parameters so packing id so we'll be packing list identifier which is the id packing list name which is the name and packing sorry in the localization okay so that will just give me packing place with no items within it while the the second one will be more fun because this will return me also parking list and maybe i'll call this create with default items something like this so i will accept packing list identifier also so if i can place id i will also accept the name okay and now i want to also include um those additional this additional data that comes from the user input so as i mentioned you can either create the packing list which is just empty and manually add every single item or you can give me some more data like where are you going for how long and let's say what's what is your gender and i will do this for you automatically so we need to provide let's say in here days gender and this localization that we have in here and of course i could do something like end days and you know and and assume that this is fine however once again since we already know the concept of of value object and we don't want to got into the primitive obsession it's probably good to have the dedicated value object for let's say for the days so let's start with our travel days i'll create the value object called travel base i don't want to to validate this within the factory because it's not the right place the factory should focus on constructing the packing list rather than validating what are the the days are correct or not so i will do travel days and this will be the record once again and yeah maybe let's just copy this from something because in many cases that will be just the same implementation of course we could think about some sort of base type which could be handy so i'll just keep it as a u short travel days and this will be the value and yeah let's say that if they the the general business value sorry business rule will be that we don't support travel that is longer than 100 days because for some reason we don't we we don't know how to construct the packing list for for such a long trip so we'll do validation like if value is 0 or higher than or sorry greater than 100 then we'll throw an exception so once again we can create an exception called let's say invalid travel days exception okay and packet exception is the one that we want to derive from and here i will just pass you short days let's create the property and the message that says value and then days okay invalid travel days okay something like this let's just make this one liner okay and now we can throw it within our constructor like this value cool refactoring this days and this will build days days this will be rather this and u-short is the one okay we've got it so that'll be the first thing so we need the travel days so days then i mentioned also gender so let's also create a gender for gender i think that we can stick to enum it makes no sense to actually wrap it into into value object but i would say it's pretty much all up to you so i could come up with some sort of const uh directory and i will do gender as an enum okay and yeah we'll have the male we'll have the female and okay let's just keep going we've got the gender okay and we also need the localization and yeah now i'd like to also discuss one more thing because at this point we have the localization and i mentioned that localization will be used to reach some sort of weather api and get the average temperature and base of this will make the decision so i would say that the at first glance it it looks like yeah we only need the localization inside our domain but later what that means is that somewhere within my factory method i'll just implement this i would need to do something like var temperature equals and then some sort of service that would based on this localization give me the temperature and i mentioned that the domain itself is not responsible for you know some sort of i o operations and we want to avoid this so how do i get the temperature and prevent my domain to to be relying on some sort of i operation especially that you know probably this call should be asynchronous so now it's turns out that the packing clips factory also will be cool to have this method also asynchronous i don't want to do crappy service dot result because that sucks and that's completely makes no sense because it's blocking so yeah that would mean that my factory actually constructs the packing list using a synchronous approach and that's kind of violating what i've said about the beauty of this approach so the answer for this question how do we actually going to tackle this is very simple it's the application responsibility to first fetch this and orchestrate and once we'll have the temperature the temperature will be basically another parameter for our packing list factory and that's pretty much oh we don't need to delegate this extraction and this calling to weather api to our domain it will be the application layer which is responsible for that because this is more like process level this is one of the steps within the process getting the temperature and this data once it's get gets transformed into a more domain friendly object can be used within our factory simple as that so as you probably expect this will be very last and i promise this is very last volley object which will wrap nicely our temperature which is called temperature hood would guess it this will be record and once again i think that i can move to i'll be very good with this cup pasting i will just change this to double because it's rather continuous there will be there is like will never have like ideally like 20 degrees of celsius it's rather zero zero zero zero point something and okay so if this temperature is let's say lower than minus 100 or greater than 100 then this probably means that yeah something is is is not right and that you're either going to like like to the moon or or to this i don't know whether we have uh the temperature greater than 100 on the earth probably not i think that 70 is like the limit all right so the exception should be created for this let's call it invalid temperature exception and yeah we can create a constructor this constructor will accept of course our double double value and we'll call our base and the message is value and then interpolated string value is involute temperature okay and of course i need to derive from our packet exception and maybe just to be consistent let's just generate the property and believe or not it's the last poly object that we've got just now the matter of few improvements in here and changing this to temperature and same goes in here and we're done so this as i mentioned will be rather the here the parameter to our to our factory along with the localization itself so this will be used only for the yeah for this assignment to within our aggregate this will be used for actually deciding which particular items i would like to get okay now the question that remains is how the heck we are actually going to decide on those items because now i've got my factory my factory is responsible for yeah returning the for returning uh this packing list and i need to somehow the place to decide what should i take so we'll introduce a very last concept also known as from the domain domain-driven design which is called the policy so we could think about the policy as some sort of domain representation of a strategy pattern so basically i don't want i want to have the coupled way of deciding and putting particular conditions within my let's say if statements to the separated classes so the idea is very simple actually we will create the dedicated classes let's say the policy for packing lists um for let's say males or for the females or for the low temperature or for the high temperature and the factory will basically will pass this those data and we'll say okay let's give me all policies that we have defined within our domain and now let's check which of them are actually applicable to our case so we'll filter them and see okay only three of seven defined policies are actually applicable because we need the packing items for mail and for the template for the low temperature and let's say for more than 10 days and we'll say okay so those three policies please give me your predefined items and inside each policy will have basically the list of some sort of items that should be taken to our journey and that's the very simple i would say simplified approach to this issue because if you would see yeah there's quite a lot of compositions in which you probably would like to exclude maybe some items but for our for our case this will work just fine um so let's start with defining the directory you will see this i think that you will get the idea almost immediately once we'll start implementation so i'll create the policies directory in here and i will create first an interface so this interface will be this sort of contract for each of the policy with the packing items so i'll just call it i packing items policy and this interface is going to have two methods first will give us an information whether this is applicable to our case or not now i'll call this is applicable and of course the natural thing would be doing something like okay i'll pass temperature right i will pass localization etc etc however over the time once we once the whole system will grow we might you know evolve and come up with some some different policies depending on maybe new factors so maybe now we add a hobbies and we'll have that and other policies for each of the hobbies so if you're interested in sport so let's say tennis you would like to take your rocket or your shoes or your equipment or maybe if you're more into let's say scuba diving then you probably take some something else so if we would extend those policies at some point we would end up with multiple parameters in our is applicable method which once again is not very i would say pretty and yeah even for the reading purposes that would be kind of pain so in this particular case it would be better to wrap this into some sort of policy data or whatever you call this but basically the idea is that this will accept this will contain all the data uh based on which the policy will determine whether it's applicable or not to this particular context so i will call this policy data and this policy data as i said will be it could be just a record for now and this will accept few things so this will be first travel days called days then we have the gender gender we'll also need the temperature i also need to call this gender temperature and alkalization could be also used all right so [Music] we've got our policy data and now we'll use it in here so within our is applicable method we can use it as follows so basically data and of course the most important the second method is the method that will return to us the innumerable of packing item so generate items okay so policy data data okay we've got our contract for each of the policies so now we can define the policy for each individual case so let's start maybe with with the gender and i will just create one example policy and later i'll just jump into already finished code because it makes no sense to spend another half an hour on generating like like some dummy items so let's start maybe with mail gender policy okay so managing the general gender policy will of course implement our eye packing items policy i will make it internal just to prevent this from further usage so internal class which of course needs to implement my two methods so first let's start with this is applicable it should be rather simple this will be applicable only if data.gender is gender dot mail okay and as a result for now i could yeah i will just hard code this of course we could think about more elastic approach in which i would maybe grab this from somewhere else uh but yeah for now i'll just leave it as it is some sort of hard-coded name this is the mvp of our application we don't want to waste our much time so if you're male you probably need a laptop for gaming and the quantity is one because you kind of need it and we also need what is packed um i think that we can slightly refactor this i think that we can assume that by default i will just assume that it's not packed i will just want to generate it so that will be rather better i think and then you'll probably would like to get some beer because you're a man and probably this will be yeah we can also hard code this we don't need it only 10 beers even if you're traveling for just one day and the last but not least maybe book because you want to be educated you don't want to be a dumb idiot so you have the book and let's say that will be more robust in here will do that actually i would like to make it i'll use math ceiling and let's just assume that yeah you would like to take let's say um we'll take the days and we'll just divide this by the seven days and yeah this is it's good to have at least one book a week okay and that's how one example policy might look like so it will be applicable only if the data dot gender will be mail and yeah this will return you those three items so let me just now jump into [Music] into the implementation i will just finish it up and you'll see the rest of the policies in just a few seconds all right i'm back and yeah i've just finished the implementation uh the one thing that is worth mentioning is that now i added sub directories to our policies so the gender and the temperature which are also the name of our value objects and the enum which yeah caused the compiler to complain about it so we just need to be now more explicit when it comes to our policy data definition so now it's like cones dot gender and value objects of temperature so just so you know and i can actually move it in here so now let's just briefly go through the gender is the gender policy we have for the female also some lipstick powder eyeliner uh for the temperature we have two so we have one for the high temperature which is as you can see uh over 25 degrees of celsius so we have the hat sunglasses green with uv filter we have low temperature which is under 10 degrees of celsius so we have the winter hats scarf gloves hoodie warm jacket and the first and if the third catalog is universal so as you can see it's always applique applicable for our uh packing list so this is why i also use the discarding here we don't care about the input we always say that this is applicable and here we have some sort of basic stuff like pan socks t-shirt trousers shampoo blah blah et cetera and this is uh calculated so let's say that for the pants i want to have let's say minimum between days and maximum quantity of clothes which is seven so my assumption is very simple if you're traveling for more than seven days that you'll probably use your washer yeah to basically clean your pants off and you don't need more than several pens probably for your trip so you know very dummy logic but does the job so now we have our seven policies and yeah it's just now the matter of using them within our factory right and that will pretty much the whole implementation and the end of our domain finally after two hours of recording so let's just finish it and see how this might feel so within our packing list factory i will create private read-only i innumerable of packing item i'll just sorry not packing item but rather high item policy which will be called policies okay and this actually will be provided to my factory so to create construct this factory you need to provide me the list of of my policies and now the implementation will be rather simple so let's start with the create since it's no brainer we don't even need this policy actually in here so for the create we'll just call our constructor for the packing list passing identifier name and localization and yeah we'll just return this and if you want to add something manually you'll just need to call method called add item which is rather in here and for the create with default items this will be slightly more let's say advanced so more data first we need to construct our data so policy data like this policy data accepting uh days gender temperature and localization so days gender temperature and localization cool now let's filter the policies so we'll do the following var applicable policies uh equals policies that were and we'll do p goes to p dot is applicable passing our data and now we'll do the following items equals and then we'll just call our applicable policies dot select many because we want to flatten the results so select many p dot p dot um generate items and we'll pass our data so this as you can see will return me the innumerable of packing item and now we can do var packing list equals and we can call this method so create passing our id name and localization and let's just call this add items method passing our items so factory will only will only take care of the whole process of the constructing but the general idea about you know protecting the invariants is still within our aggregate the aggregate knows what rules needs to be fulfilled to actually add those items to it so we just don't want to lick this is why we prevented this leakage and just not to put it in here and we can return the packing list all right and that's pretty much it when it comes to our factory so now we have like almost everything we have the factory which is responsible for creating our packing list we have the policies which we can just i wanted to to note one thing that it's quite easy to extend if you would like to add more factors on which will generate the list we can just add new let's say sub catalog add maybe those hobbies or something and create the policy for each individual hobby which would give you the additional items uh of course once it's once you got into this domain you'll start analyzing this you will notice quickly that it's not that easy and probably there might be some sort of conditions that will exclude each other but for the very simple application this will work just fine and the last thing that i mentioned on the during the introduction is the repository but of course only the the interface which will be just some sort of contract so what i'm capable of doing with my aggregate so i will just add the directory called repositories so repositories and in here i will add interface called i packing place repository okay this will be an interface so what operation will be allowed on my packing lace uh repository so i will define few uh first of course i would like to get my packing placed by the identifier so i'll just call this get async and i will pass the packing list identifier which will be our id and maybe a few more and i will just remove it so first we'll be adding then we'll have the update and we'll also have the delete now there are two things that i want to mention um in this specific implementation so i'll just do maybe packing this will be better name okay something like this okay believe or not that's pretty much all we have within our repositories inside the domain so two things i wanted to point first is that as i mentioned the this is the contract that specifies what we are capable of doing with our if our domain in our example it will be rather looks like a crap right so i can get update delete but maybe sometimes this won't be a case maybe i could create some sort of aggregate but i cannot delete it so this is also the the some sort of answer why i'm not relying on any some sort of generic repository i mean the generic repository in general sucks in most cases if you're not aware of some sort of pitfalls that you might fall into it's better to rather you can still use it if you want but rather it will be in the composition and not directly so of course in here i just want to explicitly limit my number of operations that i can perform my aggregate and yeah inside of the specific implementation somewhere on the probably infrastructure layer i could do whatever i want i could use a generic repository i could you know inject the road db connection and that's just fine but using one repository contract for every single aggregate might be dangerous because there might be a different life cycle of each of them so that's the first thing second thing which i want to cover is this so i was talking about this i o operations and that the domain is pure and we don't rely on any i o operations i also mentioned this during the factory that the application layer will be responsible for retrieving this temperature yet still within our contract definition i've got the async so it's some sort of abstraction leak right and i totally agree i agree that this is an abstraction leak and the reason the only reason that i'm putting this is because there's no better way of defining my contract because now assuming that i would just remove it so i will just make it packing list and those three void now my implementation in the c sharp itself let's say on the infrastructure layer also needs to be synchronous right because in here i define the interface as synchronous so this is some sort of c-sharp specific topic which yeah i just i just cannot overcome the limitation of my language i believe that in java this could be slightly different because they're using i think the attributes for the asynchronous jobs so there could do this in more pure way but in this i don't want to make a trade-off or in this case on the performance and making every single call to database um built on top of you know synchronous connection and making this as a blocking operation i want to make it asynchronous because you know frank an exception comparing to getting quite a lot of data from database in synchronous way is significantly different story so i would rather want to be a pragmatic and yet this will be the only some sort of sign of io operations within my domain that i could allow this task and this async keyword sorry this async suffix in my method name and that's only because c sharp does not allow me to do it in any nicer way all right let's just briefly summarize what we've done so far within the domain itself so we started with the entity so just to remind you the entity as the object with its own identity it doesn't necessarily mean that you need to create an id which is artificial sometimes you may look for more natural identity like the example with the with the email address of the particular customer in our case the entity is also an aggregate which is some sort of simplification but basically just to remind you the aggregate is the guard of the consistency and atomicity within the single transaction so if something needs to be atomically changed within single transaction in our case this should be wrapped into into the aggregate and the aggregate is just this object representation of our transaction boundaries within specific bonded context but in here i don't want to go into the strategic domain driven design topics um later we also added the value object so once again we wanted to avoid this primitive obsession code smell and also we wanted to delegate the particular validation of the data primitives into its own object so each of these value objects is responsible for server validation and for a nice encapsulation of of those primitive values because data types given by the c-sharp are just the data they do not encapsulate the behavior they're just the containers for particular data and yeah the behavior is something that we really care about within our domain layer besides that just keep in mind that both valley objects and entity slash aggregate make the validation which might cause an exception and the reason for that is that exception will immediately stop the execution further execution of method or the constructor we just don't want to rely on some sort of high high level uh high level services or high level objects let's say in the application layer that will eventually validate whether what we've got within the boundaries of our object whether this is actually valid or not we just if something basically breaks our invariance within within the boundaries of our object we want to immediately yeah just stop the execution throw an exception and yeah and return the response to the color with the information that sorry but we basically cannot process your request and uh yeah we also added the domain events domain events basically are some sort of consequence of decision that we've done with the encapsulation so we don't have any public properties within our aggregate we only have the identifier which is publicly available when it comes to getter the other properties like the name or localization are just the implementation detail the aggregate is not responsible for giving you this data we don't want to allow the situation which someone let's say on the application layer builds some weird logic built on top of their public properties we assume that yeah everything besides the identifier is just the implementation that i want to hide it so as a consequence of this because we cannot make the assertion let's say in the unit testing we need to make sure that once i will call some sort of method on my aggregate let's say at item i want to make sure that this actually behaves as expected so as a consequence and some sort of output of my aggregate we added the domain events which is just the representation that some significant change has been made within our domain so this represents something that already happened within our domain layer and yeah we added also a few let's say tactical ddd building blocks so we got the factory which is responsible for creating the packing list this could be either the list with no items or the list with pre-generated pre-generated items and if you want this second overload underneath we'll use the policy which will be some sort of strategy pattern more or less strategy pattern in which each particular case will be put within once again separated class so we're not afraid of the amount of classes that we have so far it's i would say it's good to have a lot of small classes rather than one huge class that will do everything and yeah if you'll call this manager or or this service it's it's like the ultimate crop that you can probably come with and uh when it comes to factory one thing that needs to be mentioned is that this temperature thing needs to be fetched before we actually reach our factory so we don't want to rely on any external io call to let's say weather api we want to do this on top of process logic pass it to factory so the factory will know uh we will have no dependency on on our i o and yeah the domain remains clean and last but not least the repository which is our contract and defines what we can actually do within with our aggregate just keep in mind that yeah this is the only place in code which kinda contains the i would say abstraction leak because we need to define the contract with the tasks and with this you know async suffix when it comes to method name because of the conventions within the language and because of the how how the language is constructed underneath that's some sort of trade-off but we want to make we want to be pragmatic so in this particular case the performance on top of database will be crucial we don't want to make the call synchronous we don't want to have this blocking operations so yeah we need to deal with that um so in our case yeah we just have this asynchronous methods within the domain but this is just an interface and implementation of course will remain as an asynchronous on and that will be delegated to infrastructure itself so i think that when it comes to domain that's pretty much it i would say that it's rather the object-oriented programming tutorial so far but that's the whole point i mean i think that it's good to have this different view on the topic sometimes i think that we as a software developers forget about basics and yeah we were thought about this and yet still at some point we might forget about good practices when it comes to object-oriented programming and and it's good that we have some sort of architecture that can support those those practices so we've finished our domain and we now need to move one layer up which will be the orchestration so the application layer so we'll see how we may orchestrate our domain how the whole use case may look like on the application level but to make it more granular when it comes to use cases we'll introduce the cqr cqrs i would say so um first we need to of course know the term so what is the cqs what is the natural i would say evolution of this which is the cqrs and yeah we'll just discuss the topic and once we'll know the theory we'll jump back to the code and yeah just incorporate this within our clean architecture alright so we finished the domain it's a good good sign we i think that we covered this in quite a details so we can move up to the next point which will be in our case the application layer and we kind of its responsibility so we already know that this will be nothing more but the orchestration layer for our domain and that will probably end up with some sort of process logic within it and by process logic we could think about some sort of in in many cases some sort of use cases representation so let's say that in order to create a parking list i need to first get the data as an input i need to reach the weather api and then maybe check whether this parking list already exists and that was will have certain steps which will be basically handled within my application layer now typically what you would do is just creating an application service for that so we'll end up with some sort of packing list service which once again isn't the great greatest name but yeah that will be probably that would be probably the convention and the only issue i've got with this particular approach is that once we'll have this application service there will be probably operations related to getting this particular packing list let maybe by identifier maybe searching and returning many packing lists maybe um the operation related to creation of this list maybe also for you know operation for marking particular item as packed etc so we'll end up with the service that would grow quite significantly and every single use case will basically impact the overall shape of this of this class because every single use case needs to be put within it so we'll end up assuming that this system would grow in the future we'll end up with quite a quite big class and of course you can say yeah but we could do the partial classes yeah but this sucks let's be honest i mean it's not the greatest design and i'm not even talking about the dependencies of the service because there might be situations in which for particular maybe for particular use cases i will need additional components maybe like email service maybe some sort of weather api for the creation so not only my methods would you know add the complexity but also the dependencies will be quite significant so what we're going to do instead is incorporate the i would say it's pattern it's rather a principle but yeah you can think it about some sort of pattern which i believe a lot of developers are actually scared of and this is probably because of some sort of misconception and misunderstanding of what actually the cqrs is because we are going to discuss the cqrs and hopefully you will see you'll find it useful and you will see how we can move from this traditional approach in which we have one huge application service to something more granular on top of our use cases so before we actually jump into the cqrs it's good to start with the i would say the concept the root concept which is called the cqs the cqs is uh one of many mnemonics that we've got within our industry and the cqs stands for command query separation now that was the concept the principle that was originally described by i believe that was the brendan mayer who was working on the i think that was the eiffel language in like 70s or something i don't remember the exact date i'm hopefully i did not screw the um the the name of this uh of this engineer but basically he came up with this principle uh with this command query separation saying that you know once you have the system and you have the methods within those system it's good to have this i would say separation between reading the data and writing the data so he instead of you know mixing this within one method i know that you probably know the methods called let's say get or create something right or get or delete i i've seen something like this the problem with such a method is that without knowing the internal state of my application i'm not quite sure which path will actually will be executed so whether this will be the get or the create if i don't know what's underneath let's say on the database level i'm not quite sure what state is going to be executed so not only for the you know unit testing it's not very comfortable but also yeah i would say that this might be a sign of some sort of bad design that maybe where we're not certain about the execution so we decided to put it together and glue this together for some reason and yeah the cqs says okay in most cases you either want to read the data or modify it so we'll now divide and distinguish two groups of methods first would be the queries so the queries basically are the methods that will return the data and as a result they by definition will not mutate the the internal state of our application which in general means that they will be pretty much idempotent so if you're not familiar with the concept of idempotency there is a formula for this that will help you understand if you know the math probably you do but in a in a nutshell the the whole idea is that no matter how many times we'll execute some sort of function the result remains the same now since we are not mutating the state this pretty much by i would say implicitly forces us to have this idempotent methods which is great because no matter how many times i will ask for data i should of course i would say the transaction off i would just uh have every single time the same result because of course you know concurrently i could get some sort of insertion which would influence impact my my end result but assuming that there will be no concurrent execution yeah every single time i call get methods or i'm asking for the data the results should be exactly the same on the other hand we'll have the commands so the command is a method which will basically mutate this state but as some sort of to in opposite to queries the command will not return any result so speaking you know in a more like c-sharp matter that would mean that we'll either return void or task non-generic or value task non-generic so now yeah just no result you either ask for data or you want to mutate this simple as that now of course someone may say okay but this is crap i mean this is because i clearly know the exceptions and let's say you know stack.pop which basically mutates the state of the stock and gives you the the element back yeah that's that's true i'm not saying that the cqs is like followed by every single api that you will find i mean it's like sort of principle which will help you to not fall into some sort of pitfalls and i can give you an example already um i think that i was like three four years ago and i was doing one of the project for uh for my for the company i worked at that time and yeah there was a another team which basically created some sort of package nugget package that was put on the on the registry so i basically used this in my project and one of i would say components that i've got in there was some sort of rich domain object that i had to reference and once i actually you know go f12 on it and i wanted to see the definition the ide only showed me like there was a get set so i didn't know at that time that there was actually some sort of logic implemented within the properties so the get actually had its own implementation when it comes to the property of the object so you know i with this without this knowledge i basically said okay this is like property that i want to use and every single time i was executing the code i got no reference exception now to me that was completely completely mysterious why this actually is eventually set to null because at some point in code i've got the value on my property now like later when i want to access it it's null and that's because this code actually violated the cqs so get on the property actually had some sort of logic that internally mutated the state of the value that was returned so you can expect that yeah i wasn't very i wasn't very happy once i actually found out what's going on um but yeah that was the of course the also the issue with the ide that ide didn't get the hint that there's some sort of implementation that was just flat and simplified version when i decompiled the code so cqs is rather some sort of good practice that you should incorporate rather than like you every single time you need to follow it and of course there are some sort of examples also within let's say microsoft api which follows it um so the good example could be innumerable which has like dot current so this could be treated as some sort of query even though it's like the property and there is a method called move next which internally changes the state machine underneath so cqs once we actually cover the the cqs we can move further to its i would say natural continuation which was defined i would say few decades later i think that was like 2008 maybe i'm not quite sure who was actually responsible for for defining the principle but for sure that was popularized by both greg young and uridahan and the term i'm going to discuss is of course the cqrs which stands for command query responsibility segregation now there are different flavors of cqrs actually and the very the one that that i'm going to discuss at first is the cqrs on the object level so cqs said okay just do the separation on the methods level don't mix rights with the with the rights and ckrs says okay you know what maybe let's just delegate rights and reads to separated objects so not only segregate reads on rights let's say on the interface but you know just put this into separate objects that would be much easier to manage and that's pretty much the only significant change when it comes to secure rs this basic cqrs now we'll have the commands which will be objects responsible for mutating the state of our application and they will be handled in specific place called handlers command handlers to be exact and we'll have another object called query and this query will be input to our system that will give us the information that we would like to retrieve some sort of information and that's pretty much it and someone may say okay so the command now in terms of cqrs is just the object that will contain the data but we will know that this leads to some sort of muta state mutation underneath so what's the difference between the command and let's say regular dto well honestly the difference is exactly the same like between the layered architecture and the clean architecture so dto as the data transportation object basically is focused on the data it's data centric it's just a dummy bucket for the data that needs to be transported the same from the client to server while the command well command will be will from the protocol perspective will be exactly the same it will be just the json or like you know protobuf xml whatever that you'll put in our api but on the application level we'll receive the object that will be more like behavior-centric so we'll receive the command that says let's say create packing list or mark particular item as packed or promote the user to administrator so the name will be imperative but the name is actually some sort of convention but the general idea about what this object represents the will of the user is something that makes a huge difference because seeing this object i already can expect some sort of behavior so this is the the input from my user and his will to do something with my system he wants to promote the user administrator and he wants to create a packing list while once i get let's say user dto to me this might be anything this could be like used for the update for the for the insert for something else i don't know this is just dummy bucket and i need to delegate this to some sort of object that will understand what what the heck is actually uh is all about in this particular context while command by nature will be more behavior-centric rather than domain-centric so i would say that this is the very simple yeah the difference between the cqs and the cqrs and i believe that that was the greg young who also i mean also one of the the guys that i really appreciate when it comes to knowledge i mean and and he also was very involved in the popularizing the term of cqrs but i believe that on one of the presentations he he mentioned that the cqrs is not it's for sure it's not architecture so we need to be clear the ckrs is not architecture and i believe that he said that it's barely a pattern i mean if this is a pattern it's one of the most stupid partners ever ever created it's rather once again a principle that you should follow because you'll either have the will to create something or to retrieve the data and you can even go further with this thought process and you can think about what if i actually don't need one system maybe i need two systems one or rather subsystems one will be completely delegated for reading the data and one would be that delegated for writing the data so the cqrs on i would say more system level could be something like this in which basically i have the command that comes to my system to my let's say api gateway or something else and yeah the command will go to the right side of my application and in here what i got i've got my rich domain i've got everything related to let's say domain driven design and etc and eventually i will store this to database which could be optimized for writing on the other hand once i will receive the query the query could be delegated to read site of my application and the difference between right and read site is that while it's on the right side i can actually think about let's say clean architecture on the reach side i'll probably want to avoid touching my domain because domain means that i want to mutate the state so i could even think about creating a projection or maybe completely different model that is has nothing in common with the domain driven design like entities aggregates i could think about very flat very thin layer that's only responsibility would be accessing the data let's say from the database optimized for the for the reading maybe some sort of denormalized sql sql database or something else or like no sql database and the whole purpose of this particular read layer will be just you know i get the query get the payload from this query perform some sort of searching on my database and return the result so i will not touch the domain and i will i have clear separation between what is the domain what is the business value and what is just stupid writing sorry stupid stupid reading from my application of course i would say it's more like sometimes i feel think that people call this like enterprise securities or something like i not only i have the separation on my system level but also the database level because like like on this diagram you have two separated database so one optimized for writing for re and also for reading of course you could still have one and maybe do the logical separation between them or just use a different representation for for for writing and for the reading it's all up to you of course if you will decide to have the two separated databases you need to think about the some sort of cost of synchronizing them because once i put something on the right database this needs to be synchronized back to my read database and it has cost also we need to think about the data consistency etc but this i'm saying is is only if you really want to have this very clear separation of what actually is a command and what is the right side what is the part of the system in which i can basically mess up because doing the read which is invalid or basically doesn't work i think isn't that dangerous but if you will calculate the discount the tax or whatever incorrectly on the right side that may be that may be an issue for the business and for your boss so i would say yeah we can think about three different levels of this separation cqs which will be more like method separation the basic cqrs that we are going to cover is basically the object level and if you really want to go beyond and you want to have this clear separation and maybe two subsystems you can have the part of your system that dedicated to rights and the other one dedicated to reads i know that what if we think about where we speak about the cqrs quite often this is combined with the event sourcing and i think that this might be one of the reasons why people are actually scared of the cqrs because they think that once they will introduce the crs they also need to introduce the event sourcing which is basically not true so if you don't know the concept in nutshell the event sourcing is i would say some sort of technique which slightly changes the data representation about some some domain concepts that you have within your system so i know that it's not the greatest example but let's just stick to it let's think about your bank account so you have probably some sort of bank account and you could think about your bank account in more like relational model approach in which you have the relation called accounts there's probably the role that represents your personal account so you will have some sort of you know id an id number your full name some other stuff and probably the balance of your account now this model works just fine and we are taught about this during whole hour career and the only issue is that this actually represents the current state of your account and there might be a case that business comes and asks for very simple thing could you tell me what was your balance like three weeks ago or two years ago with this model you don't know because this actually represents your current state of bank account you have no information about anything that happened within the past and of course you can think about some sort of audit that you could maintain along with your let's say business data but not everybody actually does that now even sourcing flips this concept in slightly different ways so instead of having just one row within my database um how about relying all concept that we partially covered which were domain events or basically the events so event represents some sort of action that happened significant action that happened within our system so instead of having just one row with information that yeah this is my account and this is my balance i could create a series of events which would represent different events within my system so there will be very initial event like i've created a bank account so i you know go to the bank and wanted to open it and then i you know withdraw the money you know maybe i got the salary to my account and i would got a lot of those events which would represent different transactions that operates on my that operate on my bank account now if i would like to ask what is my balance like my current state i would basically take the very initial event apply it and then every single event that happened at the end and was stored inside my database would basically change my let's say domain object and eventually after applying the last event as a scalar i would know that let's say i've got 100 bucks on my bank account so i'll basically know get the the whole sequence of this and the whole stream and as some sort of projection i would know that yeah this is your current state but the beauty about this approach is that now if you think about it i've got very detailed history what actually happened with my account over the time and you can even think about some sort of time traveling so if the business comes and asks the same question what was your account what was your balance like three weeks ago or two years ago the only thing i need to do is to apply a filter so i want to do this projection of my events but only to a certain point of time like i i'm literally writing like where and let's say date time equals x and i'm applying this every single event till this point and i will know that let's say i've got 1000 bucks on my account now of course someone may see and spot one issue so in a previous approach i've gone i've got only one row that i just had to retrieve to my let's say application while now especially when it comes to bank account and assuming that i'm very active user of this platform i may produce like thousands of events so not only i need to retrieve them and process within memory to get the final result what is my current balance but yeah i'm i'm suffering performance wise because i need to get this data from database and perform them and process them within my memory and that's true so of course the even sourcing will come with some sort of optimizations like some snapshotting so every let's say 100 events i will do the snapshot and i will not once i will would like to know the current state of my domain model i will not start from the very bottom but from the last snapshot etc but at some point even if you're performing this optimization business may may come to to you and ask for i would say one of the most common requirements could you create a very simple statistics we would like to know how many millionaires do we have in our bank so in the current state approach you would do something like you know find all the accounts within my one table which have which which have basically the balance column value greater than one million and that would be simple count right you basically do the count on the predicate you got the result boom now when we think about the event sourcing this is more tricky because even if you are applying those snapshots and optimizations it's not that easy when we try to implement this ourselves so now to find out what is how many millionaires do i have i will need to basically retrieve every single user apply the this user into my domain model in memory and once i will do this i need to apply this this predicate because i cannot filter this 1 million balance on the database because only the only thing i've got is the sequence of of of the of the events so based on one event i can i do not know whether this actually will whether this particular user actually have one million dollars on his account so i need to get the sequence for every single user apply this got the current state of it so the scalar and once i've got this list of my all users i need to apply the predicate which is just insane i mean this is literally insane so even sourcing itself is great technique and especially if you think about systems that will require some sort of undo operation so let's say that our packing list will have this feature of undoing your changes at any point of time this is great because i've got a few i've got whole sequence of events what you've done so far with this particular packing list and that's great however if you don't need such a let's say functionality or something more specific that would require this uh this approach i would say it's just when it comes to reading it's it's just a killer and now this is where we get back to the cqrs because even sourcing itself is not optimized for reading for efficient reading especially where we think about big volume of data its purpose is completely different so if you want to have the system that is efficient not only for doing this projection for one single data model but also for let's say you know some sort of statistics for the business and etc and basically interacting with multiple domain objects you need cqrs because cqrs gives you this um defeat this differentiating the right and reach side so on the right side i could apply my you know events event sourcing and i would eventually do the projection only for let's say one aggregate while these changes will get propagated to reach site and maybe database optimized for the reading which could be let's say just regular sql database which will keep this data in current state model so i will have two databases one optimized for even sourcing purposes and the second one basically for reading because i don't want to read from the event store which is you know the name for the database of those events so if you have the event source sync you'll probably need the cqrs because otherwise any i would say any more advanced query will basically kill you while on the other hand once you have the cqrs you don't need necessarily even sourcing i mean if you don't have to yeah you can just incorporate the cqrs and the separation object on the either object or the system level but the the projections the events are not necessarily needed so i think that this is uh crucial to understand the concept and people also you know frequently ask about this okay so what about the cqrs i think it's kind of kind of over overhead for my for my case no i mean you will see that this literally is just few interfaces and just like one class which will make your system more granular on the use cases level rather than having one huge application service and we it has nothing in common with the with the event sourcing so let me just check whether do i have and if anything else but i think that's pretty much it i just wanted to point this and i believe that there was a question on youtube whether we'll do something on the event sourcing probably yes and probably not by ourselves only because there are quite a few people that we know that are mastering the even sourcing and maybe we'll think about some sort of some sort of cooperation and someone who's will be more qualified will explain this whole concept in detail i'll just give you the helicopter view of of what is this concept and why there are a few challenges with it but it's not like the cqrs requires even sourcing even sourcing by its nature will require cqrs so i think that's it when it comes to theory we can jump back to the code and let's just implement our application layer all right so let's implement our application layer and i think that when it comes to cqrs we'll start first with the command so with the right side and before implementing any specific use case within our application layer i think it's good to start with some sort of abstractions first which will represent both the commands so our behavior centric object input from from the end user and the handler which basically is the class responsible for processing this particular command so i will jump to our search abstractions and add another directory called commands and let me just add few interfaces so first will be our i command so once again this will be nothing more but a marker interface for the generic constrain purposes and another one will be called i command handler of t so i command handler is the name of the command and we'll add this constrain so where the command needs to be both reference type and it needs to implement a command and inside i'll just add one definition for our method which will be just method that returns task and i will call this handle async so i would say that in this particular case we will be quite orthodox where it comes to [Music] this principle so yes yes we will accept the commander will mutate the state but will not return any any data from our handler of course this will have its i would say consequences which we'll describe later but for now let's just leave it as it is so we've got our both command and command handlers and one thing that would be cool to add is some sort of i would say mediator between the color of this handler and the handler itself because if we think about let's say api and let's say here we have the controllers we'll probably have some sort of packing list controller which would need to execute our application logic so typically what you would do is basically creating some sort of private read-only i command handler of t and let's say some sort of command type and this will be executed in one action and the other one of another t would be also needs to be injected and used in the another action so eventually i might end up with a lot of command handlers being injected into my controller because every single one will be dedicated to the separated action within my controller now this is something that i would like to avoid because i would rather keep the responsibility of finding the proper handlers to some dedicated components so in addition to what we've got in here i will declare one more a very simple class called i command handler sorry i command dispatcher so as the name says its responsibility will be basically to dispatch the command take the command look for the handler that is registered within our application resolving it and executing our handle async method and that's pretty much it when it comes to the dispatcher so the dispatcher itself won't be generic because this would make no sense but the method which will return the task so this patch async will be actually generic so in here we'll have the generic parameter of the command and this t command of course will be our input and once again we'll pass the this constraint that the command needs to be a reference type and implement i command just keep in mind that this i command needs to needs to refer to actual um i command marker interface because there's also windows input and you will see this later that yeah there's also i command defined within the within the uh windows namespace so if you are worried about this you can think about slightly different name but for me i command it works just fine and of course this dispatcher will need to have its implementation and of course quite typical when you will see um like blog posts or maybe other video courses you will see that the cqrs is built on top of mediator library and that's perfectly fine i will just leave it to you i will not do this because to me it's rather simple and of course i would need to define the request handlers and my interfaces would need to implement them so i would rather want to keep it simple and i will build this dispatcher on top of regular i service provider which is nothing more but the container for my dependencies within asp.net core application but of course if you have a will or maybe some specific task now and yeah you need some sort of more flavor to your cqrs i think that mediator is one of the best uh choices that you have available at least in our dot net world so i want to create the implementation for my dispatcher but this will no longer be an abstraction but rather the implementation so this of course needs to be put into our shirt shirt class library so in here i will create the corresponding commands directory and in here i can create the the actual uh implementation i can call it like in memory command dispatcher because of course we could think about like sort of you know remote executing uh remote execution of this command maybe i would like to call like external servers or something but yeah in our case that will be everything could happen within the memory so in memory command dispatcher and as i mentioned this will of course implement our i command dispatcher now one thing though is that i need the reference to our abstractions from the shirt package just like this now it's visible i can implement this i will make this also an internal because i don't want this to be public to anyone and yeah let's just create a private read-only i service i service provider okay so this is the service provider i can inject this make it more like one liner and the implementation will be rather straightforward i will mark this as an asynchronous and let's just create the scope first so service provider dot create scope okay and this scope will as you can see this requires the microsoft extensions dependency injection abstractions so i'll just we'll just reference that particular project probably i will need to uh there's always some sort of issue so let's just explicitly add this dependency injection abstraction which is in here maybe the issues that we've got already a 6.0 rc version so let's just reference to 5.0 let's just add it yeah and now create scope is available for us so once we've got the scope i need to resolve the handler of course i will assume that there's only one handler for one method there is no need to have more than one command handler for specific command type it makes no sense we'll have like delegating we'll delegate this to one specific handler so service provider dot get required service and in here i will have i command handler of t where t is of course the command and once we have the handler we can call await handler handle async and pass the command of course if if you'd like to be more i would say follow the standards when it comes to the asynchronous jobs you probably would like to pass also the cancellation token and put this into the signature of this method but i'll just leave it simple just not to produce too much code now of course we need to also register our in-memory dispatcher within the ioc container so i will create extensions class so this will be public static class which will contain the registration logic so this will be called during the configure services within this configure services method so i will just reference to i service collection so this will be returned and i will just call this add commands and i will say that this will be extension method on my iservice collection services i can return services already but i will add the registration this could be either singleton in this case so like add singleton i command dispatcher and then in memory command dispatcher another thing which could be quite handy is adding some sort of automatic registration for all the handlers within the application so instead of doing this explicitly every single time that i will add the handler to my application layer i would like to avoid the situation which i need to remember about the registration because it's rather straightforward and each of them will will be probably implemented as some with the scope lifetime so it would be cool to have some sort of automation code for the registration process and sadly the asp.net core container does not provide such a capability of some sort of automation the scanning of of my assemblies and automatic registration however there is very cool uh library that we mentioned few times on our youtube channel called scrattor so scrattor basically gives you two great capabilities added to default dependency injection container which is basically assembly scanning and automatic registration and the second capability is decorator pattern integrated with the whole ioc so i will just reference the squatter within our packet shirt so let's just do scratter and use the 3.3.0 yeah i'll just install it and i will do the following so services and now i should see the method called scan and i want to say that once i will actually i would like to scan the assemblies so from assemblies and i need to pass as you can see the patterns of assemblies and i'll do the following the assembly that i will scan will be the assembly that actually calls this particular add commands so that will be the assembly dot get colic assembly okay all right so we'll have this add commands and once we actually have it i will do add classes and this class need to needs to be assignable to actually i need to use this non-generic version so type of i command handler of t and once i have it i can say that i want to implement this as implemented interfaces i'll probably need to do this in here okay as implemented interfaces so every class that will implement i command handler will be registered as i command vendor of specific t command and with mentioned scope lifetime and that's pretty much it i can now safely use it in my application so maybe i'll just do this right on and just not to forget about it so that will be the very first thing that we'll do within our application uh application layer so somewhere in here i will add once again we'll have this convention that every layer besides the domain because we don't want to have this i service provider within the domain layer so every single layer beside besides the domain will have these extensions and once again this will be static okay and here i'll do the following so public static i service collection of t sorry not of t but for either i service collection so i'll just call this add application okay that'll be this i service collection services okay now what i miss is this dependency injection abstraction however i don't need to reference this directly from my application because the only thing i need to do is just reference to my shirt so this is what i do i've got shared so now i should have an access to my service collection interface and i will do return services and now in here i could call services.add commands so that basically solves the issue with further explicit registration for every single command handler within our application layer now one thing though which we also need to be aware of is the fact that in here within our domain we got few types which also needs to be registered so we've got our factory for packing list and the second thing are the policies which we also defined within our domain and this also needs to be registered because for instance our you know packing list factory accepts this and yeah we need to get those this iron rubble of ipicking items policy somehow and of course this will happen yeah thanks to thanks to our container so because i want to avoid the situation in which domain will register this this explicitly within the domain i want to keep it very clean the application extension will also handle this type of registration so besides our add commands i will add also registration for the factory first so i will just leave it as a singleton makes no sense to choose any other live lifetime so i packing list factory will be implemented as packing laced factory and yeah at this point of course we could see clearly that i decided to make it internal so there are a few a few ways of dealing with that you can either mark like within the domain that the internals are visible to the application or you can basically yeah just screw it and yeah make this like public sealed and make it public because maybe you would like to be pragmatic and don't produce the code that would be crap so for me okay i will just make it public but it's your choice i don't want to um i don't want to say that this is like the best approach but the one that will produce list code and the very last thing when it comes to our ad application is also something that we've done uh within our command handlers so i would like also to automatically register every single policy that will eventually add to our domain so if any other developer comes up with some sort of policy for our packing items i would like to automatically register it and yeah i don't want to bother him with this responsibility of of uh declaring this and and adding this registration to our to our dependency injection container so i will do the following services.scans or something that you already know and let's just do b goes to b from assemblies once again and i would like this time to refer to very specific assembly so in this case that will be the domain so i could do something like type of ipacking items policy dot assembly so this will give me the the the reference to particular assembly which in our case is domain and once again add classes c goes to c assignable to and this will be i packing items policy once again as implemented interfaces but this time i will just register this with the singleton lifetime because yeah we have all those all those um policies are actually you know kind of hardcoded so in our case that would just work so yeah i would i would say that this is it when it comes to our registration process within both domain and application and of course this code needs to be needs to be called somewhere so of course our entry point to whole system will be presentation layer which in our case is pack packet dot api and within our startup maybe i'll just clean clean this up a little bit somewhere in here i will just call services. at application so as you can see the application of course just to remind you the api will see the infrastructure but indirectly we'll also see the application layer because the infrastructure can see the application so this is why we can reference this with no issue to our configure services and now this method will basically will be responsible for not only adding our inventory command dispatcher but also for registering the factory and all the policies within the domain layer so i think it's a good time to actually jump into our application layer add first command and eventually we'll also add the command handler which will execute the whole process logic of of our application so within our packet application i will just add new directory and i will just call it commands and in here i'll put the definition for our commands so as by the convention uh or the convention i would recommend when it comes to our commands would be give the name which will be imperative and thanks to this you will have an ability to completely omit the command suffix so in this particular case i would like to create the command which processing will end up with creating the packing list with pre-generated items for our travel so i will call my particular command create packing list with items so kind of longish name but i think that it's still fine so create packing place with items and yeah by just looking at the name i will immediately see that this indeed is the command so of course i need a few things in here and first and foremost i will just put the i command interface because i want to explicitly say that yeah this indeed is our command and now i will need few details within my command that will be used for the whole processing so i will just make this a record and the parameters i would expect from my user would be the following so first i would like to have the identifier for my packing uh for my packing list then string name and just keep in mind that on this level on the application level i don't actually use the [Music] the value objects to me the command itself is of course it's like the object which is behavior-centric but it comes from the from the client it's more on the transportation level i would say so in here i don't really mind to have the primitives it just doesn't bother me because eventually this will turn into the into value objects that we defined within the domain so we expect the identifier the name and now the parameters that will be used for this items generation so first i will just pass the u short which will be days so days of the the length of our travel then the gender so in here i could either try to um pass the number or i'll just leave it as it is so that'll be just much simpler so gender and then we need to pass also the localization now as we already know the localization consists of two strings actually so this is like the city and the country and of course there are a few different approaches how you can actually uh tackle this so you could either pass like one string and maybe split this on the ui with like comma or something else and now try to make this some sort of composition and extracting this piece of data from the string or you can basically wrap it into some nice model and put into our command so i'll just do this as an example and i usually like to call those models which are let's say more complex objects within my command i like to call them uh right models so just like you have typically like read models on the read side and here i will just have the right model so write model is the part of my command but not the command itself and it's as the name says only used for the writing purposes so i will just also create this as a record and i will call this localization right model and in here i will put both city and the country just like that so now i can use it and i have my command definition now the next part is of course having the handler so usually what i do when it comes to the file structure is the following within my commands directory i will just create the subdirectory so right click directory and i'll just call this handlers and in here the convention will be the following just name of our command so maybe i'll just copy this to avoid any sort of typos and handler suffix so create packing list with icons handler and once again i don't want to have the explicit command word in here to me this actually by the name convention gives me enough information that the address indeed is the command and i will just mark this as i command handler of t where t is our t command and this is why we had to mark create packing list with items as i command so just like this and we have now our handler being defined now what i would like to do in here is of course few things so if we would jump back into our factory within the domain now we can jump into our interface so this is the method that i would like to eventually call right so we already have our id name days gender and localization itself however we need the temperature as well because we already discussed that yeah getting the temperature information is rather part of the process logic rather than the domain logic because the domain just expects that we have this domain that we have this temperature information and so this is something that we need to get on the process level so for sure that will be one of the steps that our handlers should perform and of course eventually we should call our factory to create the packing list and at the end of the day we should also use our repository which is defined in here to call our edge async method and put this somewhere eventually probably that would be the database but for from the domain's perspective we don't care where this aggregate actually gets persisted so in here we already know that what we should do and just before i will execute both this uh methods responsible for getting the temperature and and calling our our factory i would like to make this command handler more idempotent so we covered the item potency during secures discussion so once again this idempotency is basically uh this ability to execute this particular method multiple times and the results should remain the same so in this particular case i would like to make sure that even though i will for some bizarre reason i will call this handler like 100 times i will only create my packing list once and of course implicitly this actually this method will be item potent and this is because we use the same identifier so assuming that we'll also always have the same identifier would probably get nasty exception from the ef that would say that yeah you try to put the element with the same primary key so this is basically not allowed but maybe i would like to avoid such situation in which rm gives me more this you know bad looking exception and and and maybe it would be also a good idea to think about my custom exception which would be more yeah say human-friendly so at first glance i would like to check whether the packing list already exists within my database and for this purpose let's say that i would like to check the existence using not the id but by the name so the assumption is very simple i can only create the the uh packing list with uh with the name once and no duplicate is allowed of course that's slightly different for from the assumption that we had on the domain but let's say that we changed our minds or the the business comes it says okay we need to check the existence of uh of this packing list uh by using our name now this is slightly interesting because now it turns out that the packing list actually has now the natural key and this natural key is name indeed because if we need to check the existence of this packing list using our name this means that there is this needs to be unique within the whole system of course our model is simplified uh quite significantly because we don't have the user definition and probably once we would introduce the users the the natural key would be some sort of composition of both user id and the name and base of those two we could create some sort of natural key composed which could be uh used even on the database layer like performance aside this could be used for for searching the unique resource within our database and this actually would not be required any longer of course for the database we would need to provide like some sort of primary key but yeah we you know without knowing it we could ask for a particular let's say packing list or any other resource in in case so i would like to check the existence of my packing list based on the name now the question that arises is okay so where do i put the method responsible for checking my existence and of course the obvious candidate would be yeah i've got the repository i've got like get async so i'll just create like task that returns the boolean because who cares we could do boolean of course we could do something more robust like some sort of response uh of t or something but we don't care let's say that we just do task.bull and exists async and in here we can pass the name so packing list name and that's pretty much it right now i can inject my repository and this repository will be used within my handler and here i will just call it and yeah if the result is true then i will just throw an exception that's sorry but this already exists and if it's false then we'll first gather the temperature and then eventually call our factory and save this using the repository once again now the issue with this approach is there are actually a few issues with this approach first is that by doing this we kinda i would say we kind of broke the whole idea about the repository because the repository as i mentioned on during the implementation of our domain layer the repository itself is rather the contract built on top of our aggregate and let's just not even now skip the aggregate term but more like domain model now in here neither uh that our our domain model is neither used for the input nor for the output right so we just get the value object and we return we have this bull being returned from the method and that's pretty much it there's no domain model being involved in this process so yeah okay we could think about this like oh yeah let's just be pragmatic and just don't complicate our life even more right we already have quite complex structure within our projects comparing to let's say clean architecture sorry uh layout architecture but then there are a few different scenarios so let's say that now at some point in other command handler i would like to perform something else maybe i would like to check whether you know some other conditions are fulfilled and for this case i would like to using let's say different parameters maybe temperature or something else i would like to check whether there is a packing list already for the same localization because maybe i would like to modify this instead of adding new one or any other stupid requirement that may come so this would mean that every single method would require adding new method for searching particular either you know of of our aggregates or something else and would end up with multiple weird stuff that actually yeah i would say it actually fits quite well into the repository concept because this is this used to be or it's supposed to be just a contract built on top of our aggregate and our domain model and now we more treat this as like sort of universal interface to which we put everything related also with gathering the data and that's something that i would like to avoid especially once we'll move to our query side because now we are only about the writing to our application but what happens if you would like to implement the query and the query handler so let's say more robust searching i would like to search using my name and maybe using my location or something else and eventually i would like to return also the result which will be probably paged so in this case yeah should i also put this into repository because if so this means that in the domain layer i need to have the concept of page result and now this is kind of weird because in the domain let's say discussion there was no page itself there was like the core domain is like packing list functionality right and this is the concept that we know and yet now in the domain i need to know let's say something related to pagination that's something weird and we'll end up once again with multiple different methods that will be responsible for different types of searching so this is what i would like to really um i would like to focus the concept of repository is built especially for defining the strict contract or on our domain model and if you need some at some point on the process logic you need to check the existence you need to have some sort of search or eventually once you will once you will shift to query site you will need also some more robust uh like functions for for retrieving subset of our of our uh packing lists the repository is yeah you could do this in here but you would end up with the repository itself growing way too much and this is something that i would like to avoid so instead of doing this like with this method in here i would rather do the following my application now so my application layer needs something so why don't we just define the contract on the application level not on the domain level and this eventually gets implemented by the infrastructure probably so in here i would just say that maybe i'll create something like services and here i will just create a very simple interface and let me just call it i packing list service maybe read service because that will be more restrict so i packing list service is of course the interface and in here i'll just put the method that we wanted to use so task that will return the bull and here we don't even use any uh specific value objects i mean we can but this is more like process logic so yeah it's it's not now it's not that restricted uh anyway so i will just put the method called exists by name async and here i'll just put string name now what it gives me is now that i have completely complete separation between the what is the domain and what operates on my domain model and what is eventually used for processing on the application layer so i don't care about the implementation yet of course and i can just jump into my handler and inject things that will be probably needed here so first is of course i will use my parking place repository because repository will be eventually used for persisting my aggregate i will also use my factory for creating packing placed and now i can inject my packing list read service just like that and let me just initialize this from constructor okay and we can start implementing our our process logic so i will just mark the method as async and i can do the following so await then our read service dot exist by name async then command and if we have our command i can do command.name and now what happens if this returns me true this means that i already have the parking place with the same name so in this case as i mentioned i would like to throw my custom exception just like we've defined the custom exceptions on the domain layer i would like to do exactly the same thing on my application level so within our application let's just add directory called exceptions okay and here i will create the class that will be called packing list already exists exception okay and i forgot about the x okay and this will derive from packing pack it exception okay so we will accept the name and the information goes here says packing list with name and then the interpolation already exists cool and of course we can also assign this to some sort of property okay now it's just a matter of throwing this in here so throw new and in here i will do the following so command dot name now this point i would like to do one more thing which i believe would make more sense and all i would like to use the one of the capabilities of our record so just to remind you we have this command implemented as a record so records implicitly uh gives you the object decomposition so they implement this uh deconstruction sorry not the decomposition so they basically implicitly implement the deconstruct method which allows you to do the following i could do var and then inside i will just put every single thing that i have so id name uh what do we have next maybe i'll just see days gender localization okay so name days gender localization okay and i'll just do command now as you can see i have multiple variables which basically are assigned uh from the command internals itself so i've got my id which is a good name days u-short gender and localization and now i can just use them as a local variables so no this command dot is not required anymore so i think it's already looks way way better and okay that was the step number one so this gives me this sort of item potency and no matter how many times we'll call our method i'm ensured by this check that the particular packing list with the name which became our became our natural kim and will be created only once now we need to gather the information about the temperature and this will be yet another service actually that we can define with our application because our application don't occur which resource will actually use to get this information on the on the application level we don't care so this could be either my local file this could be some sort of web service or you know i could create a request to the moon and back and maybe there is some sort of station that will gives me such an information i don't really care how you will actually implement this i will just define a contract and this contracts should basically be implemented somewhere probably once again on the infrastructure level and should provide me the information based on the input i will give you so in here i will just create an interface and i will call this i weather api service this could be something like this or maybe more something more maybe service without api because api already suggests that there will be some sort of api underneath so i'll create eye weather service and i can jump back maybe first let's implement this that will be also cool and this will give me some sort of response maybe for now just don't define it and i will just call this get weather async and as the as the input i will use our localization value object that we have so let's just now focus on the response so response will be probably some sort of once again read model or the dto that comes from somewhere but this could be either api or some some other source of this information so i will just stick to name dto but you can do whatever you want actually so in the application i will create directory called dto and i will put another one called external and that's the convention that yeah you can adapt or not basically external means that we are the consumers of this dto if something is uh in the dto directory uh directly this means that we are producing this dto and the external just says that yeah this is something that comes to our system rather that our system produces so external so clearly to distinguish those two concepts and i will call this weather dto and this actually i could actually make this also as a record so weather dto i will not change the um the payload itself this could remain the immutable so i don't care in this particular case so let's say that this will be double because this probably should be double i mean the temperature isn't always let's say exactly 36 degrees of celsius it's rather than continuous the value so in here i will just put the double temperature okay and now i can use it use it as the expected result of my dto sorry of my weather service action which in this case is called get weather async and once again the beauty about this approach is that at this point i don't even know how am i actually going to gather this information and yeah the reason i'm doing this because i don't really care this is not that i should be uh bothered about at that point i just assume that i will get this eventually and how i'm going to do this is just implementation detail so i would like to call my weather service to get this information so first i need to construct localization i partially have the localization in here however this for now is implemented as a right model so localization right model so i will just maybe change the name slightly to localization right model because localization is the value object that i would like to create so localization equals and in here i could do new localization and that will be write model dots city and localization.country okay now having the localization i can safely call my weather service so weather equals await then weatherservice.getweather async passing our localization and now i can perform maybe some sort of check so if this weather is null for some reason maybe i got the typo in my either country or the city and yeah basically this resource couldn't give me this information yeah once again this is the business decision so what i'm supposed to do in this case so do we even care about the fact that we don't have it okay maybe the the packing list won't be as precise as we would like to uh because the temperature is basically not uh not fetched from the service but maybe for our for our application this weather information is critical and we will just want to avoid the situation in which uh yeah in which this happens so we can have this assumption that if weather is now we want to throw an exception uh once again and and basically yeah abort the whole creation process of this packing list and one more thing that i would like also to discuss is this difference between the exceptions and on the application level and the domain level because someone could say okay but why these exceptions are defined both on the application level and on the domain level why just don't get this thing into our domain and just completely get rid of the exceptions on the application level well to me it's like this exceptions on the application level basically are belongs belong to process itself so parking list already exists so if we think about this do we from the domain perspective know that something already exists or not i mean the scope of the domain is quite narrow and it's probably the scope of one particular one instance of let's say our aggregate which is packing list so packing list from the packing lists list perspective itself it's like it's always present it's all it always exists while eventually on the [Music] application level we may have this information that okay but we wanted to check whether this exists and this actually uh is so we are want to inform the user about this this situation but it's slightly different level the application you need to remember that the application orchestrates the domain so during this process uh we discovered that we have a conflict on the name and we want to inform the user while once we'll actually start performing our domain logic we on the on that level within our particular aggregate we might have a different issues like in here so this is something that we need to distinguish what can what should be defined within the scope of our aggregate is basically all the you know value objects that we have within um or what actually should be thrown as some sort of part of our process logic so in this case because the weather comes naturally as some sort of result from our process logic i would like to put this into rather application application level because domain expects that yeah will basically give you the temperature right uh sorry nothing here but in here the temperature is always always present it's not nullable so it makes no sense to say like temperature is null or is empty because the domain definition doesn't get the concept that this this might be null or not it always needs to be present to to call this method so let's just jump into the exceptions and create the one so maybe missing localization weather exception okay and once again that will derive from packet exception okay and i can pass the localization as a whole okay the message so couldn't fetch weather data for localization and here i can do localization.country maybe slash localization.city i'll just assign this to property and we can now use it so somewhere in here for all new okay throw new and we'll pass the localization okay and now the last part which is actually the most important so creating our packing list so packing list equals and now we can make the usage of our factory so factory dot create with default items and we can pass our identifier name days um gender now weather dot temperature and localization so it's good and at the very end away dot repository at async and list so that will be whole process logic that we have within that we have within our handler first provide some sort of item potency um by checking the existence of the name and for this purpose we create in this very simple abstraction that will gives us this information we don't want to we don't want to put such weird i would say methods into the repository because the purpose of this repository is slightly different it's not like just dummy container for for every single operation that is connected to our database it's rather basically the contract for our aggregate now we have the localization and we ask some sort of resource for this piece of information for now once again from the application level we don't care and how we'll actually provide this information whether this will be some sort of external api or or anything else we check whether we have it this is this assumption that we just need the weather for the further processing and eventually we call our factory which underneath we'll use the policies for creating this default uh items and the returned packing list is just persisted once again somewhere because we didn't have the implementation yet [Music] and that's pretty much it that's the whole definition of our process and it's what i really like about this is like in this particular case and this is something that i partially covered in the security introduction is like if you would have one huge application service for everything related to packing list that would be kind of weird in terms of dependencies that we've got passed into our constructor because for this creation process we not only had to fetch the sorry inject the weather service but also the factory and for any other like the updates or for the deletes we'll probably not gonna need it and probably also the read service won't be even used so let's say for the update and for the delete the only the only needed dependency would be repository yet still we would have to um every single time we'll have to inject those three as well and of course if we'll have different types of actions within our application then yeah eventually we might end up with one um one service which would accept like like 10 dependencies because each of the action would require different different components so in this approach it's it's more granular and it's more like on the use case level and every use case might have different dependencies and we just provide them individually rather than having one global container for for the whole process logic and that's really uh really cool so um because i don't want to bother you with with all the possible use cases that we might have because i would like also to have the within our application uh something responsible for uh adding the new packing item maybe marking this as a packed maybe removing the whole uh list yeah there will be quite a few scenarios that we could implement so let's just use the magic of movie editing i will just do the cutting here implement this and you'll eventually see how the other handlers will will look like and we'll jump into the query so the read site of our application okay as you can see there are a few more commands that we have now within our packet application so let's just go through them and eventually we'll also see the the handlers that will process each of them so the create packing list with items was the first command that we have and now of course once you have the list you can uh you can add or remove some sort of items so let's say that we have like add packing item this is the another another command that we have and this accepts three things so packing list identifier name of our of our item and the quantity same goes for removing of course we have also the ability to remove the packing item and this accepts the packing list identifier and the name of the particular item we also have the management for the list itself so we can remove this packing list completely and we have anything more i think that that's pretty much it oh and we have the pack item sorry so we can basically mark particular item as packed so maybe some sort of flick will appear uh some sort of icon that yeah we already have it within our luggage so let's maybe start with maybe with the delete packing list that will be quite easy so for deletion we basically use our repository to fetch the packing list this actually has a typo so i'll do this like this so packing list we're checking whether this is null if this is not then we want to throw an exception that you want to remove something that does not exist within our database and if this is not a case we basically call repository dot delete async passing our packing list and that's it for adding the items so let's say this one once again we are getting the information about um packing list and if this is now we are throwing an exception and then we are constructing the packing item and we are adding this to our packing list and then we call update async same goes for the removal stuff so in here i'm checking the packing list then i'm removing the item by calling this remove item method and i'm calling update async and as you probably expect same goes for the packing sorry for the pack item so i'm getting the packing list and calling basically the method on my on my aggregate so it's rather straightforward once you actually get the idea it's it's it's like no brainer you basically try to orchestrate in a very simple matter the whole process uh which accept the command and eventually probably call our repository because at the end of the day this command needs to mutate the state somehow of course there might be situation in which this will be slightly off the domain maybe more infrastructural concept so i'm not saying that in like 100 percent you should always call the repository at the end of the the the handling the handler itself but in most cases like 95 would probably end up with with some sort of um repository call of course once again just the matter of the style because as you can see the packing list and checking this null existence is quite repeated in this of course you could think about some sort of maybe extension method that would be added like somewhere in here like fro if not found or something it's the matter of whether this actually bothers you or not to me if if this does its job and i'm focused only on particular use cases it's not something that i would um it's not something that basically bothers me but it's it's all pretty much up to you so this is how we are going to tackle the rights to our application right we are just talking about the the rights to mutating the state and yeah um that would that will be pretty much it and and of course and of course at some point we would also have to also have to implement the reads from our application and the reads as we already know are basically built on top of the queries so queries will return us some sort of result but they will not mutate the state of the application so what it means is that ideally query should be completely of the domain should not touch the domain itself because it it doesn't actually makes much sense uh if my only purpose is to retrieve some data do i really need to construct the whole aggregate and you know use it for for the reading i mean for us it's even more uh i would say makes less sense because everything is basically hidden besides you know maybe besides the the identifier itself but we can we cannot easily access and create the predicates even complicated predicates on top of our private fields and we'll see this once we'll actually implement the whole the whole repository and and the query handlers on the infrastructure level that it's rather gonna be quite complicated and this is once i would say pros and cons of this approach i mean it's it's really hard to implement this efficiently but on the other hand maybe this will convince you not to use your aggregate also for the reading so we'll get to this uh point later and we'll discuss the whole issue but but but at some point this is something that we also need to to cover but of course we cannot jump into the queries already and that's of course because we don't have the definition for the query and for the query handler and probably for the query dispatcher so just like we've done with the commands in here and in here we need to provide both abstractions and the implementation for the query handling and eventually we'll jump back to our application layer and continue the whole implementation process so let's start with the abstractions first i'll create a directory called queries and first link will be of course adding the query definition so iquery actually that will be an interface so interface i query so i'll just create two versions first will be this for the generic purposes once again and the second one would be i query of t or maybe t result will be even better so t result which will implement this i query okay and now the interface iquery handler so i query handler off and this will be slightly different because i will accept two parameters first will be tquery and the result will be the second one and now i can put the uh basically i can put the general generic constraint which would said that the query needs to be class and so we know the class but needs to be the reference type and this also needs to implement iquery of to result and in here i will create the definition for t result handle async i will just stick to this convention this naming convention and the query will be accepted as a parameter so i will i will accept the query and i will return just the the result of course in here i can make this now in okay and we can already know we already know that we'll probably need some sort of dispatcher so let's just define this within our abstractions so i query dispatcher okay and the dispatcher basically once again will accept some sort of query and will return as the result so t result is the one that we expect i will this this time i will call this query async but this could be like dispatch async whatever the result and as a parameter i will expect i query off to result okay so uh let's just jump to shirt next once again we need to create a directory queries okay and in here let's just create in memory query dispatcher okay this dispatcher i would say is gonna be slightly more complicated and that's because now we have to construct the generic type within it so i will do i query dispatcher so just like this i can make this internal sealed class so what i need inside is of course my service provider so private read only i service provider service provider okay let's just make this prettier and in here i need to first create the scope so using var using var scope equals and then service provider that creates scope then i need to resolve particular i query handler of the result tquery so to make it happen i will just use the reflection so handler type would be type of and then iquery handler of the query to result and then make generic type and inside i will put both query.gettype and type off to result so i'm what i'm what i'm doing is basically i'm getting the types of both query and the result and i'm putting this into those two as a generic as a generic arguments and now i can resolve use this type because this of course gives me this handler type is of type type and i can use it for my service provider to give me a particular handler so that will be just the matter of var handler equals and then scope dot service provider then get required service and here i can pass my header type the issue is that as you can see the handler now is returned as the object because i've just provided you the type so naturally the returned this handler is of type object so to make it work i will do the following i'll just already return this because this will of course uh return me the result and i will do await then handler type and then once again i will use the reflection so get method i could either hardcode this but i would recommend using the name of operator from the c sharp i don't remember which one is probably seven or six i query handler of let's say i query of result and to results this is just to give me the query uh sorry this this this okay so basically this will just return me the string which says handle async but if you would like you could just remove it and put into regular string if you are ensured that this method will uh sorry like this if you are just ensured that the method of our handler will always remain like handle icing you can do this but i will just stick this name off and this will return me the method so this could be potentially nullible but i will just make this assumption that it's it's not and i will just call the invoke and now on the invoke you need to pass the object on which i will call my handle async method and this object will be returned handler and i will need to pass the parameters to my handle async method and my method accepts only one parameter which is the query so the way to do this is even though i have the only one parameter i need to create the um an array and pass the query and the reason this is actually still red is because invoke also returns the object and object by definition is not nullable so i need to explicitly say that you know indeed this will be the task of the result so to sum up what actually happens in here is that the the issue that we had is that we couldn't ask for i for iquery handler of of iquery of t result because that would basically return us a null uh so so to prevent this situation we basically constructed the generic type so we just said that this is the template and in those two generic arguments we need to put the particular type so we are getting the type from the query we are getting the type of our result we are putting this in here using the reflection and now this will be the proper query handler that will be eventually implemented somewhere within our application so the handler object should be returned however now we have the issue because this is of type object we cannot call the handle async so we are using the reflection once again to call the method called handleasync and we want to call this on our handler object and the passing parameter will be just the query because the handle async only accepts one uh parameter and we are saying that yeah this invoke will actually result with task of the result so we can safely await this and that's pretty much it so now it's just a matter of once again doing the automatic registration and uh already registering our in memory query dispatcher so i'll create extensions extensions so public static class and you know i think that's i'll just use the copy paste pattern for this and so let's just move in this add commands i will just move it in here okay to make this more granular and do the following so just copy this okay resolve add commands now it becomes add queries and in here first i need to register the in memory query dispatcher okay and now i just want to automatically implement everything that implements iquery handler okay and yeah that's pretty much it now it's just a matter of calling our add queries and we should be ready to to go now i want to [Music] discuss actually this method and where should we call it because obviously once we'll get back i think that i can now collapse okay once we actually have the both commands and queries definition the the obvious choice would be to put the queries and query handlers on the application layer right because yeah this is quite natural i mean the command which were responsible for rights are within the application and you know i was saying a lot about the process uh plot process logic etc so naturally since the cqrs is that the concept of the query and the command is in terms of security is tightly coupled this means that both commands and queries should live in the same in the same layer right so in this case the application layer well i would say yes and no and of course this is once again just a matter of of your opinion uh but to make it more clear let's just add one simple query as an example so within our application i will just add queries directory and once again i will have this naming convention that if something is like get or search i i i will just knew that this is rather the the query so i will just i made it completely the query suffix so let's just start with something simple like get list okay so get backing list is our query and i can mark this as i query off and now at this point it would be probably a good idea to come up with some sort of um either once again read model or i will just stick to this dto convention that i'm expecting like some sort of packing list dto as a result so let's just maybe add this first and we'll eventually get back to the discussion about the uh about the queries so let's start maybe with more granular stuff like localization so localization dto so localization dto will have like two things first is the city and then we have country okay so we have city and country uh in this case uh i'm living this with the public getters and setters because i'm the producer of my dtr i'm it's not like in this case like with the weather dto which was the result of calling some sort of probably external system but in this case i am creating this and i don't care on the read side i don't really care about the hermitization because it's not all about this i if i want to automatically or dynamically during the execution of this query add or fill this properties i have the i want to have the ability to do this so since i've got the quill separation on the domain and the reads in this case i don't care about the you know this class being like hermetic or something now i can add the packing item so packing item dto um and once again prop string and that will be running name okay and we also had quantity so the quantity and bull which says whether this is packed or not okay and last but not least is of course our packing list dto so the packing list dto will have identifier then we will have string name then we had localization i believe okay and the list of our items so packing item video items okay now i can use it as the my t result and of course for the query i can have you know the payload that will be used for for constructing this particular result so of course for this case it's rather straightforward because i will just accept like the identifier and based on this identifier i will find particular packing list name of course this since we have this assumption that the name is like sort of natural key i could also use the the string name for this purpose but we can stick to to the identifier itself now let's just try to implement this okay so handlers we already know it so this convention will be also the same so get parking list handler and let's just implement this like get packing list and the the expected result will be packing item dto uh sorry parking place dto okay implement implement and we are ready to go so our job in here is to return the packing list dto based on the based on the identifier provided within our query so in here it's rather straightforward right because we have our repository so i packing list repository i will just inject this in the constructor so now it's just the matter of doing packing list equals and then i need to make this async so repository dot get async and here i can pass query.id and in here i will do like return parking list and assuming that this is now i will return the null and if it's not i will probably have some sort of extension method that will make this dto and it's rather straightforward right like no brainer so to me this looks good right i mean we we use the repository and the method that was given to us by retrieving the packing list by identifier and the only thing that bothers me is the fact that we actually touch the domain i mean the repository by definition needs to return the domain object so fear theoretically there is once again nothing that could stop me from doing like you know calling some sort of packing please dot at item and eventually calling my repository once again to modify the stage while reading so i could do something like this this this i mean it's completely stupid i know but once again i didn't provide the environment that would this allow me to do sort of thing but yeah this is just the matter of i would say theoretical assumption that someone would like to to mess up with my query site however completely uh completely skipping this this particular topic let's just jump into another example of my query and discuss it so i will just add something that will be probably uh required at some point so query that will return me not the one packing list but maybe a few different based on some sort of maybe search phrase so typical search in which you type some phrase and you get the filtered result so in here i'll create a query called search packing lists and this will return me i query um for now i'll just stick with the innumerable but eventually probably i should change this to some sort of page of t where t is packing list dto so packing list dto and as i mentioned i will just pass one parameter called search phrase okay we have our query so now it's once again the matter of implementing this so i query handler search packing list and this will return me i innumerable of packing list dto okay okay so the handler is in here and now let's just discuss how we are going to implement this because this situation within this particular let's say reading scenario is completely different from this one because in here i had the method that was giving me one packing list however i don't see anything that would accept the string or anything that would be even close to string and would return me multiple packing list aggregates so once again i wanted to jump back to this topic and discuss what should we do of course i could do like something like task return that returns like i innumerable of my packing list right and in the query sorry in the command side i said that yeah this exists async was slightly dumped because either bull or name was not the domain model right in here it clearly is the part of the response right so something like search async should be should be just fine so string and that was like search phrase now the issue that i have with this particular thing is that once again my domain got dirty with some sort of search ish stuff i mean the search was not part of my domain language so during discussion of the domain there was never something about the searching searching right at the domain the core domain was the packing list and the capabilities of managing this and generating yet still at some point i wanted to add to my contract to my aggregate contract the methods responsible for searching but what would happen if i would expect the query to return the page result so does it mean that now paged is uh should be present also within my repository so should this become the part of my domain probably not and just like we've done with the read read service for our for our packing list the reason that we've done this is to to completely prevent the situation in which our repository gets bigger and bigger and gets uh and quite a lot of unnecessary terms are passed into our methods so why should my domain and my from my aggregate perspective i should really care about something related to searching so even on the exception level we've got this distinction that if something is not found or already exists this should be put into application level because it's more related to the process to the process logic while in here while my repositories should be responsible for searching this is something that i would rather would like to separate this um so we know that repository itself is i would say it's not a good place to put such things and of course the another thing which would probably kill us at some point is that we might have different searching i mean our application is just plain simple but what you have different types of searching like searching by name searching by localization searching by combination of those two should every single search should have this separated method with complicated name like search by localization and temperature async and you know what i'm where i'm going with this like every single scenario should be wrapped into method and should have its unique name and at some point this search might be so complicated that that you would end up with the name which is completely bizarre i mean would be ridiculous ridiculously long or you would end up with something that is maybe not precise enough like search async but there might be different criterias for the searching so i've i used to i've used to do such things and i uh yeah and we are basically ended ending up with the methods which were like 10 words long and it was just completely stupid when when while reading the code so first is like i don't want to put this into repository now knowing this that my domain should remain clean and knowing this that i probably would like to avoid the situation in which i'm getting at this point my aggregate completely because i don't want to execute any domain logic now there are a few different things that i could do about it so first thing is okay i will create the method in my packing list read service like in here and i will now be smart enough to do the following packing list dto so now it's better because i'm not touching my i'm not touching my domain it's just the already prepared result which gives me the details and i'm using the abstraction that will inject into my query handler and that's already better than you know playing with with the repository however we still remain with the issue of naming our methods i mean in this it's plain simple but once we'll in dec introduce more robust searching with different criterias these methods will just be completely ridiculous when it comes to name so another thing is okay maybe let's just yeah that's that's a good point let's just don't do it and yeah the the easiest way would be to basically operate on the sql connection and return this and there will be no necessary no such thing like wrapping this into some sort of methods would be necessary right and that's true so why don't we just put the ef core package into our application and in here i would just do private read-only and some sort of packing list or maybe packet db context right that i will create within my application layer and in here i will just use this db context to yeah call my sql and gather the information and make the projection directly on the dto so i'm not having additional methods uh with stupid names i'm not touching my domain and yeah i'm just returning the row result directly from my uh from my query handler and that's almost ideal except the fact that by doing this we actually kinda destroyed the whole point of our application because the point of application was to focus on the domain orchestration and basically on the use cases while being completely off the implementation we are not aware about the implementation while in here yeah of course i could make this assumption like okay i will just use this ef core only on the on the read side but once again there is nothing that basically stops me from injecting this db uh db context into my commands now because i don't have the separation where it comes to the layers so you might end up with the same with the same issue that we've discussed with the with the layout architecture so we are not relying on the abstractions anymore i mean i could create as much uh as as many abstractions as i would like to but somewhere internally i'm depending on the implementation detail which in this case like is the is the orm and this kind of kind of destroys my um whole concept of of this architecture being let's say clean so i would say that the only two possible scenario uh that are acceptable for me uh are first is like separating the commands from the queries completely so you would create like application dot writes and application dot reads and there will be just this assumption that application dot reads can have this uh i would say i wouldn't call this abstraction league but yeah you you basically can have this uh direct dependencies to your uh infrastructure because you don't care in there right the domain is is on the right side not on the read side or if you don't want to have even more projects the easiest way would be to keep the queries definition on the application layer but the handlers will be defined within the infrastructure layer and within the infrastructure since this is all about the cross-cutting concerns and all about it do you know everything which is technical yeah in there we can inject safely db context and or any other connection to our database because yeah we'll be within the infrastructure and we don't care anymore about the abstraction leaks we are on the technical side of our project and now this implementation of each particular command handler will be rather a technical concern so this is what i'm exactly going to do and that's because i don't want to mess up with the structure and i would also like to avoid this unnecessary abstractions on top of db context which would yeah would be just weird and actually it makes no sense to create the abstraction on top of such thing like the like the query and specific query because you would end up with this naming hell so that would be pretty much it when it comes to the application layer so application in our case will be responsible pretty much for the right side and in here we have this nice structure when we have the commands and the handlers while yeah the queries definition could live within the application layer uh as well but the handlers will be basically extracted to prevent this abstraction link and will basically implement them on the infrastructure level all right so now it's the time to finally implement our infrastructure and everything related to to our uh infrastructure of course we'll start with the most important stuff so the whole rm configuration uh because we'll need this to finish our query side but eventually we need also to implement the read service and the repository that will be built on top of our sql connection and of course you know within our infrastructure layer we also need to provide the implementation for our weather service um and at the very very end we'll also tackle i would say more cross-cutting concern concepts like error handling because so far we are throwing our custom exceptions but we don't actually handle them quite nicely so this will be also the infrastructure responsibility along with maybe some sort of additional logging i would also like to show you how we can add more um i would say crosscutting concern flavor to our handlers without actually changing the implementation of uh of them on the application level so but yeah first things first let's start with the infrastructure and the orm configuration so within the infrastructure we need two packages so first will be of course our ef core so i will add this with version 5011 so install okay and the second one would be the ef dot postgres postgres sql but that will be right either the entity framework core okay so this one so 5010 all right so once we have it i will add the new directory called queries just to move it already so this goes from application to our handlers i can of course now change the namespace to packet infrastructure so as i mentioned queries on the application will be just the definition for for the contract and the implementation of the handler will remain within the infrastructure later so that would be it now i would like to already define the extensions just like we've done on the application level so let's just make this static and just copy paste the code to avoid any issues so without within our infrastructure instead of calling at commands we already know that we'll call actually add queries because eventually underneath we are getting this calling assembly for the scanning purposes so this is crucial for the implementation and now i can call this ad infrastructure from our entry point which of course is here so maybe in here all the services that add infrastructure okay so this is already wired up and we can start focusing our our on our rm so for this purpose i will create a directory called ef so entity framework but you can call it whatever you want so now a few things needs to be created before we actually implement our query handlers of course at this point we need db context that comes from entity framework core but as i mentioned earlier it would be cool to have the clear separation between the reads and the rights and it doesn't mean that i only want to have this separation on the handle level so in here like i have the everything related to my rights and in here i will have everything related to my reads the issue with let's say one generic domain sorry db context that will be used for both rights and reads the issue is that if for the database representation we would use this model so the packing list i mean for the ef core it's it's no big deal uh we just need to provide a parameter less constructor which could be implemented as a private so i could i think already do this so private parking list this is parameter less and yeah that would be the only thing required for the ef core to actually use this representation also for the database um but the the more i would say serious issue is once we would tackle the searching because if i want to make the search based on this phrase in here uh at some point i would like to create the predicate and now the predicate cannot be defined as a expression func uh within my ef chord because everything in here is hermetic and hidden uh behind the private fields so ef core provides you this capability of shadow properties and you basically can create still the query for your sql based on the strings so let's say that i would like to search the packing list by name so i could basically put this name into the string and yeah at some point the the driver for for my sql would construct the proper handler that would return me the proper result but writing the query on top of the strings when the ef has quite good capabilities of this compile time validation on the expression level is something that yeah i would like to use actually i don't want to rely on the strings and not only because it's not as pretty as the as the expression but it's more like error prone i think so the idea is very simple we underneath on the database level we will have just one table sorry relation that would get this information about each individual packing list of course we'll have another relation that would represent the packing items etc but we'll build two different db contexts on top of that so first we'll basically treat packing list as our database model and this will be used only for the right purposes since the only public the only public property which is the identifier is sufficient for our repository right so the repository only requires id for the searching while everything related to read will have its own representation on the ef level which basically be pointing to the same table but the representation will be completely alemic so there will be public getters public setters no methods no behavior because it's more related to the database and thanks to this we within our queries actually query handlers we will have this freedom of creating any predicate that we would like to all right so just to make this clear one database underneath one table but two different data sorry db context pointing to the same table and that should be just fine so to make it happen we i think that we can start with the maybe right uh with this read models this is this is how i want to call them and we'll proceed further with the definition for our contexts and of course at some point we also need to provide the configuration so first directory called models and this models will contain definition for three different read models so just like we've done with the maybe actually you know i think that i can just copy paste this because this is pretty much most of the stuff will be quite similar so instead of doing uh calling this dtr i will call this read model okay and i can already i think change it to the proper namespace okay so for the localization that will be something like this for the uh packing item i will just change the name packing item read model now here is something that i need to point out um for the packing item i mean each item i mean the packing item itself is relation one too many right so packing list contains many multiple packing items so this is relation one to many and this means that each of them will have its own table underneath for i mean the implication of this is that we need some sort of primary key that will be used for our packing items because we had this assumption that the packing name itself only contains name quantity and and this simple flag that that will inform whether we've packed already something or not but we need some sort of primary key just like with the packing uh list so for this purpose i will just add the id and this is also another i would say good implication of this separation because i'm not forced to put artificial identifier to something to my domain if i don't need it right i mean on the domain i still have just three properties while in here for the reading purposes yeah this is some sort of limitation of my mental model of this representation that i'm using relational data models so by the convention i will just need this uh but yeah since this is the read site i can do whatever i want and this does not impact directly my domain and also because i'm using ef core i can add some sort of navigation property so maybe i'll just point that this item belongs to packing list read model which i need to first name properly so read model and now i can use it in here just like that okay so now this is the representation for my read site within the within the list i don't think i need any further changes rather than putting this as a eye collection so i collection of tea i can also could think about some maybe adding some sort of versioning if i would like to so version because my representation for the aggregate contains this just to remind you so aggregate root contains this version property and of course version is was something that i didn't put into the detail on the transportation layer but for the persistence is something that i would probably appreciate because i could create a concurrency top token on top of this on top of this property so identifier version name localization of course now needs to be changed to localization read model and list of our items should be just fine and that's first step now second step we could focus on defining our db context so another directory contexts okay let's start maybe with the read so read db context okay so in here i will make this enter now actually actually you know i think that we could also make everything in here also internal just to ensure that this will stays within this particular layer so a read db context will derive from the original db context provided by microsoft entity framework core package and in here i will define only one db set so the db set in here will point to our read model representation so packing list [Music] read model representation packing lists would be the name and get set for our property now the constructor which actually should look slightly different because that's rather db context options of t where t is our rate db context okay so options and we want to call base options this is no not needed and i will already create protected overwrite on model creating so once i will add the configuration for my db context this needs to be called right in here but i can already do one thing so model builder dot has default schema and this schema will be called let's say parking okay now let's do the same for the right so write db context uh actually i think i can pretty much copy this so this this also needs to be internal sealed okay and in here the db set will be of type packing list so as i mentioned the ef core as long as you provide him a clear instruction of how each type should be represented on the database level it's yeah it doesn't care uh whether you your model is anemic or whether it's kinda uh you know it encapsulates the properties i mean in this case it's uh the only thing that needs to be provided is the parameter less constructor so this is why i had to explicitly define this within my aggregate in here since i don't have any explicit constructor i have this default parameter less constructor uh provided so no need for explicit declaration okay we have the both read and write read and write contexts of course just keep in mind that the schema will be exactly the same there's no need to make this logical separation because underneath i just want one table and one representation for my reads and writes contexts so now quite important stuff which would be configuring because while in many cases like this we are using the [Music] the uh primitive types it's la it's like no-brainer for the for the ef core to make the assumption that okay this will be like the number this will be n var charge of some sort of uh capacity etc however once we go to our right side yeah in here everything is put into nice you know from the domain perspective nice valley objects but ef core would have an issue with defining okay so to what type i should actually uh cast this and store within our database so we need to provide this sort of explicit configuration which will help uh proceed this conversion from one type to another so from our domain to persistence and from the persistence to the domain once we'll get the data from the from the database so to do this i will add another directory called config so config and as you probably expect will have two different configs both for two different db contexts so i think that we can start with the read because this will be way way simpler so read configuration and this configuration will be basically once again internal suit class so internal sealed class read configuration which will implement i entity type configuration of t and this t will be packing list read model so this is first and i will put this into same class so packing item read model okay so i should end up with two different configure methods first is for our packing list second one is for the uh for the packing item so let's start with the packing clip street model first i want to say that i would like to create a table with the specific name for my packing lists and this will be called basically packing lists of course if i don't put this in here the ef will come up with some sort of default naming convention but if you want to override this you can just use this particular method and i would like to explicitly say that my packing list has key and this key is id okay now another issue is this localization read model so maybe i within my table i don't want to create another relation that would be uh containing our localizations i would rather want to store this localization one field in one column in my table as a just string so i will create very simple conversion from the localization width model to the string and vice versa so for this purpose i will just type builder dot property and i want to point specific property in my read model which in this case will be localization and then i will just call method has conversion and in here you need to provide the conversion so first is as you can see um convert that would be which one um convert to provider there should be something like this probably um yeah in here so convert to provider expression which basically means that how would you like to store your data on the sql level so for us i would like to just store localization as let's say country and then city separated with some character so for this purpose i would probably need to add in our localization read model some sort of simple maybe tool string method overload that would gives me this information so i could basically do public override to string and let's just come with some sort of representation i'll just return maybe city and country something like this and we can already think about conversion from the string to localization read model so i will just add public static localization read model create so create and this will accept the string as the value and yeah first we need to split this so split localization equals value dot split and we'll use specific character sorry i need to put this into as a char and i would do return new and then localization read model with city being split first and country being split localization.last so something like this very simple conversion from string localization read model now i can just uh use it within my within my conversion setup so in here i'm setting that l on the database should be basically stored as a string and once i will have the fetch process then string should be created using this create method okay and at the very last step i would like to explicitly define the relation between our packing list and packing item so i want to say that has many so our packing list has many pl goes to pl items i will have many items with one and then packing item goes to packing item those goes to this and that's pretty much it when it comes to this configure method and in the second one since there is no conversion needed the only thing i need to provide is builder dot to table and i will call this packing items okay cool now just not to maybe forget we can already wire this to our create model creation so i will do the following bar configuration equals new read configuration okay and then model builder dot apply a configuration for packing list read model that will be the configuration and the same goes for the packing item okay so parking item read model and that's pretty much it i can omit this this code in here okay so now let's jump into configuration once again and create the one for the right so right configuration yeah this will be yeah slightly more i would say advanced because we basically have quite a lot of value objects which needs to be represented on the on the database level somehow so internal sealed and our right configuration is once again intt type configuration of t where t is in this case packing list and the same goes for packing item okay this one let's just once again implement to configure methods and yeah let's start with the first one so once again i will say that builder dot has key so pl dot identifier okay this is my primary key now i need to create the conversion for uh actually for two things for if you jump back to our domain i need to conversion form for this so packing list name and also for the localization because these are two properties that i've got on my aggregate so for this purpose we need to create the conversion so in this case i will create separate converter so let's start with the localization first so localization converter equals and now we have this class that comes from the ef core so this is not something that i've created so value converter so converter of the model t provider so in our case t model is basically localization and we want to represent this once again as a string and of course we just need to keep in mind that both conversions when it comes to localization needs to match because both contexts will point to the same table so this is why in the value objects localization is represented as city and then country and not the other way around and the same needs to be applied also for our localization rate model it it just need to match because other otherwise we would have some sort of uh word anomaly once we will try to read the data either from the from this context or from this context so in this case i want to create the conversion so once again once i will try to convert the localization to string i will just call overload it to string and once i would like to do the other way around i will call localization.create passing the value second one would be packing list packing list name so packing list name converter equals new value converter and in this case we'll have packing laced name which will be represented of course as a string in our database so plm goes to pln dot value that's the representation in the database and plm dot new and here will be new and plm okay so packing list name does not have any sort of static factory or so or something we just have the constructor and the and this uh value so this is how we want to make this conversion from one type to another on the ef level okay now let's add the uh the conversion from for each of the uh for each of the properties that we have so let's start maybe with builder dat property pl pl dot id of course our identifier is also wrapped into valley object thus we need to provide the conversion for for this so in this case once again id dot value and id goes to new parking place identifier passing id okay that's first one second conversion uh this conversion is slightly different so builder dot and of course i can do something like property and property let's say localization and that's because i don't have the access to my localization right uh this is rather private field so in here i need to do slightly different thing so i need to specify the type of my property and its name so the type of my localization is type of localization and the name is underscore name sorry localization localization okay now i need to provide conversion so has conversion and yeah and this accepts the value converter and this is why those two needs to be extracted because this overload does not allows me to do this directly uh as some sort of expressions for this has conversion method so localization is passed in here and i will just tell explicitly that this actually has column name called name okay uh i'm not quite sure what i'm keep saying name because name is the second one and it's always looking at the okay so localization uh with the capital l and no underscore i don't want to have this and of course this is just uh i need to force my orm to have the same column names for both rights and and in the read db context of course for the read i didn't have to put this put this a has column name method because my um because my packing clay street model defines this in a perfectly fine way okay let's just jump back to our configuration and do exactly the same thing for our name so this case property type of and packing lists name of course you already know that we need to put the name then has conversion we are passing our packing list packing list name converter and has column name in this case it's gonna be name okay and at the very end i would like to explicitly say that our packing list has many and has many what has many packing items but once again this is hidden behind the private fields so i would like to do the following parking item and the name of my collection is just items and this should go to table called packing list okay of course you could think about extracting this to some sort of constant strings just to make sure that both this and um [Music] did this it's exactly the same it would make much more sense than than my implementation but yeah i'll just speed it up a little bit and see the actual result rather than you know refactoring this already for the packing item this will be rather straightforward because we need to provide the information for our packing item that this actually contains uh an identifier so as i mentioned for the reading it's straightforward we just added this representation because we'll use it internally within the infrastructure but for our domain we don't want to add this identifier so we are using the shadow properties uh capability of ef which allows us to add the properties on the orm level uh without changing the implementation of the model so in this case i just want to say that i will add this shadow property of type good and this will be called identity id so our identifier and i will also do the following so builder that property pi goes to pi dot name and i will also point the rest so quantity and is packed in this case of course i've got the access to my properties because it's value object and at the very end i'll do builder 2 table and once again this needs to be exactly the same because we are pointing to the same table okay so now it's once again just the matter of applying this configuration to our adb context so maybe i'll just copy paste this okay so this one will be rather right configuration and i need to import this and configuration will go for the packing list and the for the item yeah and that's and that's pretty much it okay now since we already have our two db contexts i think that this could be a good point to generate the migration because we'll need to generate it and yeah we could see what actually is being produced by our uh by our migration and i think that later we can proceed with the implementation of our query handlers and the repositories at this point i would like to register my two db context into dependency injection container so of course to create the db context itself i will need some sort of connection string to my database and we may probably expect that we would like to avoid a situation in which this connection string is some how i would say uh hard coded into our application it makes no sense because every single time we like to let's say change environment we'll need to recompile the whole code so of course for this purpose we have our app settings that are part of our asp.net core application so in this case our presentation layer and yeah up settings are just the best option for us to uh to store such settings and of course the beauty about this approach is that we can override this on the fly let's say during uh build process so within our app settings i will define the section called postgres and in here i will have one property called connection string so connection string and the connection string goes like host equals in our case localhost locale host okay database name so database equals maybe packet then username will define the default user as a postgres and the password is null we don't have any okay now of course it's now the matter of getting this settings this connection string somehow and ideally would like to put this into some sort of c sharp representation and of course asp.net core has this capability and capability and this concept of i options and the reason i yeah i mean the eye options itself is a great feature especially that if you would like to maybe do some sort of hot swapping during the run time uh it's provides you some sort of capabilities of let's say doing the snapshotting of your options but if you are ensured that this will not change over the time the thing i don't like about the eye options is that this actually wrap the object and the c sharp representation into another generic concept so this i options of t and it just doesn't look that pretty so if you would like to have just uh this c-sharp representation without additional wrapper uh we can quite easily achieve that so maybe let's start with the this representation of our postgres settings for uh within our infrastructure and we'll see to what this will lead us so in here i will define options and actually we could either leave it as it is or i could even move it to my ef so this will be only you have specific option so within the options i will create class called postgres options and i obviously got an issue of typing postgres and typing in general so postgres options public string connection string okay and i would like somehow to bind this up settings uh upsetting section to my c sharp object so for this purpose i will jump back to our shirt because shirt seems like a good place to put such a code responsible for uh yeah for wiring our our settings so we've been shirt let's let me just to create directory called options so once again i would like to stick to some sort of naming convention so it'll be just much easier and within the options i will create the method called extensions and that will be of course static as you know and the code is the following public static then t options and then get options of our key options okay this needs to be invoked on i configuration so i configuration needs to come from somewhere so as you can see microsoft extensions configuration abstractions is the place in which the i i will have then access to my to my configuration so let me just install it and of course it's once again if you want to have because this is like the abstraction so this abstraction could be easily moved to shirt dot obstructions but if i don't need to use it within my abstractions then to me it makes no makes no difference frankly speaking so this configuration and the second parameter is the name of the section so section name or what i mean by the section name is let's say in this case postgres so i will just use it for for getting the a particular section from the up settings and putting this into c sharp c object representation um i can add the generic constraint which will be actually required so our t options need to define parameter less constructor and then we'll do the following so var options equals new t options and then configuration.getsection passing our section name and then bind bind and then our options okay and yeah that's a quite common issue when it comes to this bind method we need unfortunately to wire one more uh dependency so that would be rider either a dependency injection [Music] uh sorry not this one this one configuration dot binder okay and now this binds should yeah should be just resolved okay so once we have the [Music] byte method working we can do return options and now our extension method is completed so we can use it so let's just get back to our infrastructure and somewhere in here i could do var post grass options equals and then i need to get my eye configuration now of course at this point there are few ways to tackle this and yeah it could be very tempting to do the following so i could do like var uh actually using var like service uh provider equals and then services dot build service provider and this service provider would be used for doing get like service or required service doesn't really matter of eye configuration uh however i would not recommend this approach uh i know that you probably could see this few times within our devmentors series either in the d shop or maybe in other materials i personally would like to avoid this because uh yeah build service provider basically as the name says builds you the container and yeah there are a few pitfalls when if you would call this build service provider multiple times there might be a weird anomalies related to your objects it's even possible to have the singleton with more than one instance so instead of doing this build service provider explicitly in here i will just pass my eye configuration and that should not bother me that much so configuration will be passed to my ad infrastructure of course now i need to change the implementation but if you would go to startup cs you could see that yeah actually i've got this eye configuration as my startup dependency so it's just a matter of passing this configuration here something more and it's just much safer in terms of the general management of your uh object life cycle so postgres options is nothing more but configuration dot get options now we can specify that we want to construct the postgres options and the section name for us yeah the section name is pretty much the postgres okay now at this point maybe we should also consider extracting everything related to the postgres to the separated extension because the infrastructure might have different data storage configuration that there might be also something related to maybe more uh some other parts of the infrastructure some sort of cross-cutting concerns so this infrastructure method could grow quite significantly over the time so in this particular case i would personally recommend doing another extensions but this time on top of the ef so if we basically collapse this you could see that this extension is only valid for our ef but we also have the global extensions for the whole layer like the infrastructure so i can make this internal in this case so internal static extensions and in here i could create like public static i service collection maybe add postgres so postgres i've got the issue with this name it's very hard for me to type i don't know why i service collection so services and of course i need to pass my configuration so configuration okay return services now i can just grab the code from the extensions in here and to me this will look way way better so services that add postgres can be already called passing the configuration i can remove it here and now my extensions will be like this i can even now i know that this will be about the podcrest so i don't mind to simplify the name okay uh so now it's just a matter of registering finally so services dot app db context and first let's start with the read so read db context is in here and i need to specify of course the connection string so that will be like context and goes to context use npg sql and passing my options dot connection string boom and maybe let's just put this in the separate line and same goes to my right so as you can see this will both context will point to exactly same database and yeah that should do the trick uh all right so for now this is pretty much all i wanted to do in terms of the overall registration and now we can move finally to our handlers and implement both of them and eventually we need to focus also on providing the remaining implementations for the abstractions that we defined either in the domain or or in the application so let's start with our handlers and there's an error in here okay uh probably for some reason this got changed uh or no okay this uses read model and it should be clearly detailed probably once i have done the copy paste and the renaming that this got changed so this should be of course dto okay so this one this one should be rather simple right because we only uh look for the specific uh specific packing list using the identifier so the way we are going to implement is the following so private read only and then db set off packing list reads model so that'll be like you can call this packing lists whatever and this will be slightly different so read tb context this is crucial that we want to use this one so db context context and assignment will be like packing list equals context dot packing lists and why is that complaining okay uh of course i need to make this internal okay now in here i can actually make this even not asynchronous i will just pass the task to the caller so the implementation will be following packing list and then i want to make sure that i will include uh not only the packing list because in here we'll have the eager loading so we need to explicitly load for the result for the end result also our our packing items so i want to explicitly say that besides my packing list i would like also to load items okay now the predicate so the predicate is like plpl dot id equals query dot identifier okay now i would like to do the select and in here i could either do new dots and now packing list dto or knowing that i will probably use this conversion also in the search packing list handler i could extract this right so this is just the i would say matter of whether you will reuse this or or no in my case i know that at some point i will i will use it uh projection in a different place so yeah i don't mind doing uh this extraction so under the queries i will do hood guess extensions so extensions or we could put this into like like some sort of mapping or whatever you you will call it so internal static class extensions and the conversion goes like public static packing list dto s dto this oh parking list remodel so read model is the one and in here let's just assign this manually of course at this point someone may say okay why you're not using something more robust like the uh you know autumn upper something uh the reason is that of course in this case i mean the conversion from one to from one model to another uh for the autumn upper is no brainer but i cannot use it directly within my uh within my ef query in here because this needs to be translated to the sql somehow so plain c sharp will work just fine uh assuming that i will not do anything beyond the capabilities of the of the ef core but you know using the auto mapper will just not work you need to first get the result as a read model and then use the automapper for the mapping between the read model and the dto so it's your call to me i i don't really i don't really care which one will you pick above are i think fine uh okay so localization dot country okay and items and in this case remodel that items and of course uh at this point i don't i should maybe probably also provide on here something is not right what is the issue let me just check i have no clue so localization dto is fine cannot convert from authorization gto to to wait what i'm actually using in here oh um yeah that's issue so localization dti is of course something that i would like to use okay so now this issue is gone and of course this is just a matter of whether this is required or not i could think about some sort of null checks here and there maybe also in here for now i'll just don't i will not dive into i honestly for at that point i don't even remember what we required this or not so yeah okay so packing item dto and name and one thing which is [Music] i wouldn't say it's like crucial but just keep in mind that of course in here i also have this identifier but the identifier was only to you know make my rm and my database happy but i probably omit this completely when it comes to the transportation layer so this will be more or less the implementation so hdto and now i can get back to my code and do the following so pl dot um s dto so at this point i'm always almost done think i need to also provide is as no tracking so i since this is only for the read purposes and this is once again another reason why this separation between reads and writes is crucial because the ef itself is quite powerful when it comes to change detection and you have this change tracker which basically sees what properties has been changed over your let's say http request and of course for the reading data i don't want to enable this tracking it's completely i don't need this because i immediately uh i'm returning this into the color which will be probably some sort of you know ui application and this tracking is basically not needed for me while for the let's say this purpose like getting the packing list by the id for me this tracking could be would be crucial because maybe at some point i will add new item or change the name of my list and this needs to be tracked by the ef core once i will call the update async and underneath implementation will call the database the tracker needs to know what actually has been changed so this also is a good i would say division between what needs to be tracked when it comes to getting so only this get async needs to be tracked and everything related to yeah to the query side yeah i want to disable this i don't need this tracking at all so as no tracking and then single or default async because i only expect one yeah and that's it when it comes to when it comes to this particular implementation now let's just jump back to the search i will copy paste this will be much faster anyway okay and in here i am i have exactly same issue so dto okay and this also of course needs to be internal okay so the implementation for the handle async will be slightly more i would say slightly more advanced and that is because we have this assumption that if the search phrase is basically null because it could be null right then we'll just give you every single list that we have within the within the database otherwise if you provided the search phrase will perform some sort will create some sort of predicate maybe built on the name so we'll just have this assumption that this actually search phrase only for the searching by the name of course once again just the matter of defining the particular requirements so i cannot make this in like this cool function way this will require slightly more effort but not too much so let's start with defining the queryable so dbquery will be our packing class dot and then include once again i need to include my items so pl goes to pl dot items i need to remember about this and then as queryable okay and slightly more structured way okay and then let's just check so check if query search rate is not null so if this is not now i need to i need to add some additional filtering so dbquery equals db query dot where and this where goes to pl and then i need to check check whether this uh contains the particular search phrase so of course it could be tempting to do the following pl.name that contains and then query dot search race however the issue is that for the ef core they of course don't know what to do with the contains how the contains work i mean you just need to remember that everything with you within the query needs to be an expression right it's the expression of funk and that's because we nee we we need this underneath tree like data structure to go through every single leaf and based on that create the sql uh create the sql uh query for our postgres so we would go through this particular this particular expression and we would find out this contains now how this contains work so what does this particular mean and what's the sql like t sql representation for our contains method so for this purposes the ef comes with some sort of built-in helper methods especially for that cases so in our case we would rather call microsoft entity framework or dot ef dot functions and this functions are basically as you can see there are plenty of them like less than same like it's like etc so i will call method called i like so this one so in this case what i why this is not regular like but i like is that this i like method will basically don't care about the uh the casing so i don't care about the casing etc it just invariant so pl.name and the pattern that i want to provide will be put within the um actually could be like query dot search phrase okay uh now if this will be search phrase passed like this this means that uh underneath on the sql bay sql database the query should be like where name like search phrase which means basically that the name needs to be exactly like the search phrase so there can be anything before and after this phrase so if you would like to have this more flexible you can do something like uh percent and then put our phrase if you want percent and finish so this means that there could be anything before and after our phrase so this will be more like the regular string that contains uh method so maybe i will just leave it as as this implementation so if our search phrase is not null we basically perform this let's say contains with the culture actually culture invariant underneath because we are using this i like method and now we can return the result which should be now rather straightforward so return in this case await so async but this actually doesn't need to be could be also maybe we can change this also too yeah not to await this at this point but we would rather do db query dot select once again pl goes to pl we already have the sdto and then s no tracking and then to list async okay so this this okay uh i was too optimistic i forgot that in here we've got the iron numerable of packing list dto and yeah in this particular case there is no conversion on the task and basically it's not a covariant so unfortunately because we have the generic collection i need to do this in this matter uh because now i have this conversion from tulase to ionumerable and it's it's not basically invariant in this case okay so we have both queries implemented that's just great and now i think that we can finish the uh i would say the implementation also for the right side so for our repository and yeah we are getting getting closer so query is done now let's just jump back to the repositories and let me just actually when i think about this since this is built on top of the ef it would be more sufficient to put this into under ef catalog it would looks just way better because we're building this on top of bf anyway so like this now i will add another directory called repository repositories plural okay so uh let's just maybe stick to this postgres so postgres parking list repository and of course this will be once again internal sealed and this will implement our contract from the domain so i packing list repository okay we have four methods that needs to be implemented so in here i will add to private fields so first is db set now keep in mind that in this point we need to use the packing list not the parking list read model because this will be strictly for for the right side of our application for the command execution so packing lists and second one is private read-only write db context so right deep context okay actually that's not what i wanted to do so that would be rather right to be context.packing lists okay and yeah let's just implement this so get async will be nothing more but the public lists now include and now it gets interesting because we would like to include the items but on the our right side this parking list is actually private field so of course this is what i mentioned that this if you would stick to just one db context and one representation every single you know including or every single predicate or even projection would need to be built on top of the strings so at that point i think the dapper would be more sufficient also when it comes to the performance so in this case i need to do include like string items and then once i have it i need to of course do the where so where dot pl sorry goes to pl id or i could even be better with this i will do single or default async and yeah just omit the where so pl id equals id all right and once again keep in mind i'm not adding as no tracking in here because i will need the tracking feature for getting my aggregate manipulating and maybe changing its state and then detecting the changes let's say in the either update or delete async so this is the first method now the at async will be rather straightforward in here i will need to make this as an async so await packing clays dot at async list and we need to commit this to this way okay and then we have the update which is slightly different because we have update which is not async and for the delete is also quite similar so async and remove first and save changes async believe it or not that's all all we have to do and of course we need to remember about registering so somewhere in here i will do services that at scoped and then i uh packing list repository so postgres uh packing list repository the actual implementation underneath okay and uh what else what else uh maybe let's at this point uh also cover the weather service so as you remember within our application which is here we have this weather service oh and we also have the read service so read service will be more related to the topic of the rm first so this one is also something that i forgot about so yeah under the ef i will create another directory called services so services and i will just grab this name and add postgres okay so internal sealed and this will implement i packing a list rate service okay and yeah as you probably expect this will be rather this will be rather simple and in this case i will also use the the db set which is pointing to our packing laced read model because i want to create simple predicate based on the property that otherwise would be hidden so actually this is wrong this will be rather read db context context context dot lists and in here the implementation is packing lists any async pl goes to pl dot name equals name and equals works for the ef core in this case i don't need to make this like function okay need of course i need to once again uh register it so services at scoped and now i packing place read service and postgres post grass packing place to read service it's done and the remaining implementation what i mentioned was this weather service of course ideally this should cause some sort of uh you know external api but you probably know the http client stuff and i i don't want to make this even longer because it's already like ridiculously long course uh so i will just create some sort of dummy implementation but of course ideally this should call some sort of api for this for this purpose so actually this should be plural so services and the implementation for my weather service would be i'll maybe call this dump whether service just to make sure that this is not production ready and actually that doesn't need to i mean when i'm doing like poc maybe i'm not i don't want to bother myself with this integration eventually i could add this but for now maybe i don't care and that's to me that that's to me fine so weather dto will give me the temperature of course so maybe let's make this a little bit more random so new random next and let's say that we will get something from the rage 5 to 30. so the reason for that is just that this will give me different uh policy execution depending on the result so as remember we have two different policies depending on the temperature one is for the temperatures above 25 degrees of celsius and the second one is for this so yeah depending on the result which is now non-deterministic we might have different uh policy execution so now it's just a matter of of course registering it so somewhere in here i could do something like services dot at singleton because i only have like this naive implementation iowa service and this dump weather service okay we are pretty much done with this and yeah the the beauty about this approach is as i mentioned and repeated myself like many times but i want to make this clear we eventually during last 30 minutes added this persistence and yeah this actually wasn't stopping us from from creating what is actually crucial for our application so this domain and the application uh layer yeah i mean now of course the the database is quite quite uh important when it comes to the overall execution of our application but maybe at some point i'm not quite sure whether i will use the eef or you know relational database in general so i could create like dummy implementation for my repository read service and anything else like just like i've done for the for the weather service and i could go and create like nice presentation with my poc how this would work implement this like in like in memory fashion and eventually swap it to let's say ef core so to me it's it's a good thing to to have it um all right i think that at this point we since the whole project is more or less building probably we can check it so this should compile just fine and at this point the only thing related to ef which is missing is of course the migration so migration needs to be generated and scaffolded and put somewhere within our infrastructure code so just once we start the application this will lead us to the database generation and eventually of course if you would like to change something within the model you need to scaffold new migration which would update the schema on the on the database level so we need to of course generate this first migration so i'm in the uh my my repository so i even got into the packet dot infrastructure that's crucial i need to go to packet infrastructure and yeah if i would like to now do the following so dot net scaffold this whole execution so dot net ef migrations so this is the part of the global tools so if you don't have it just type net global tools ef and this will this should install you the this entity framework global tool for your.net cli so then you have the net ef and then migrations you want to add new this is the name so i will just call this init read and then i need to point on which db context i would like to execute it so for us since both contacts will point to the same table there's no need to scaffold this twice for read and for the right this is just a matter of executing this once and the reach basically should work just fine assuming that we keep keep both of the models like i identical in terms of you know data types and the names and then i need to point the startup project so in our case this is the packet api this is the startup project because this is actually the project that has the entry point to our application and the output for my migration should be ef migrations so when i type enter as you can see the build is started and this is what i told you the build itself needs to pass in order to create the migrations however we can see that the packet app api doesn't reference microsoft entity framework core design and we need to reference this to our entry point in order to make it work so this is something that yeah you might like or not because why i've within my api which is responsible for this for handling like http uh request what i need to put anything related to my rm well you you cannot overcome this quite easily i would say uh so it's it's just some sort of convention that you need to follow and you cannot do much about it so in this case i will just reference this chord design into our api since this is my entry point to application i'll just install it and once it's done let's just jump back to to our execution and see what will be the result hopefully this will be done and it is actually so um i've got a warning that i'm using also my entity framework tool is slightly off the version so i'm using 5410 so assuming that you haven't got the uh entity framework tool before you should not have this uh this warning so let me just go to infrastructure and yeah indeed we have ef migrations and we have the first migration being generated so we can have the information like we'll have the table called packing lists and we'll have like four columns so id version name localization we also have another table called packing items and here we'll have identifier of my items so this is like the shutter property that we created name quantity is packed and the of course foreign key to my packing list table so some other some other stuff like the foreign key definition like their the default indexes etc so now once i will actually run my application i would expect that yeah this actually gets called somehow by the by the ef core and the database should be should be created so let's just give it a try and see the result i've got postgres running on docker so file type docker ps you can see that i've got uh postgres indeed and this it's running on the default port which is five four three two and i also have the data grip configured with this postgres connection and yeah for now if i will refresh this i only have like this default database and i don't have this package database created so let's see what will happen once i will just hit run of course now my application is being wired up at some point yeah it's running at this port 5000 and let's just get back to our data grip and refresh and actually there are no databases being created there's nothing between nothing besides my default postgres database and the reason for that is quite simple we need to call the method on our db context which is called migrate async in in order to actually apply the migration that we have scaffolded in here and yeah since now we are missing this this migrate async method within our code we cannot create the database based on this code in here the alternative approach is to do this via the cli but i would rather want to keep this migrate async somewhere within our code so i will do very simple thing we'll just make the usage of one of the asp.net core capabilities so hosted service which basically gets us two life cycle hooks uh start async and stop async and on the start async which is invoked once the application is as the name says starting i would like to scan the assemblies find every uh data sorry db context that we have defined within our let's say infrastructure and just manually call migrate async on it so for this purpose uh someone somewhere in the shirt i will just create a catalog called services of course this could be like the question whether this should belong to infrastructure or to shirt i mean this could be i think quite fairly put also in the infrastructure but yeah i would like to just distinguish some possible short concepts uh along from the infrastructure but yeah in our case most of the code that we have in here could be also put you know defined somewhere in the in the infrastructure and that should not bother us bother us that much um okay so in within the shirt uh we need the ef packages probably so i will just put them into the shirt and this of course means that once we'll reference the okay once we'll reference the shirt within the infrastructure we could get rid of the we could get rid of the of the entity framework core and the possibilities but for now there's no direct reference from the infrastructure to the to the shard packages okay so assuming that we have it now i will just create very simple class called app initializer and this class will be internal and will implement i hosted service and this i hosted service of course needs needs to come from some some sort of nugget package so as you can see microsoft extension is hosting abstractions once i have it i can implement this start async and stop acing life cycle hooks so when it comes to the stop so this will be called during the graceful shutdown of our application in this case i don't really care about that much so i'll just return task that completed task in this case i will need first my service provider to have this capability of resolving uh some sort of db context from my container so i'll create private field i service service provider okay so service provider and in here what i'm gonna do is the following so first i would like to create the list of my db context types so i will just type db context types and now i need to scan the particular assembly so this could be either like app domain current domain or maybe something more specific but yeah let's just do up domain current domain get assemblies and then i need to do select many and then a goes to a get types so get types okay so this will give me innumerable off types and of course now i need to predicate to filter the the one that i'm actually interested in so a dot um actually this will be other way around so type of db context assignable from a and i also want the a not to be an interface so interface a uh this actually is assembly this is type okay so type of db context is assignable from a and then okay a is interface not quite sure why this actually is not working a okay select many is the one that i was looking for so i need this to be flattened so is interface and i want a not to be the db context itself but rather the concrete type okay now this will give me should should give us in our case our 2db context that i have now i can create the scope so using var scope equals service provider and then create scope and now i can create the forage loop so for h and then db context types and here db context type and i can resolve now the db context so scope that service provider that get required service and this will be non-generic version so db context type and i can safely cast this to db context and if this is null which should not happen basically i can just do continue or maybe i could for an exception that would prevent me from doing some stupid things but yeah at this point i think it's it's just fair to to do the continue and await db context dot database and now i can do migrate async and pass our cancellation token and that should be pretty much it now of course it's just a matter of um calling our actually not calling but adding our hosted service to our application so at this point i think i will create like extensions in here so we'll make this static let me just grab some grab some method already to prevent me from doing some stupid mistakes so add shirt this is the name of the method i don't think i will need the configuration here okay and within the shirt i will just do services dot at hosted service and this host service is of type app initializer okay and let's just grab it and call somewhere here so services dot at shirt and yeah now once we will actually start our application we can actually create the [Music] the breakpoint let's just run it and see what we actually got from our app initializer so as you can see where we are here so the start async and the types that we have let's see what we've got in here so we've got two write db and sorry read db context and right db context so as exactly like we expected and now on each of them we'll just call the migrate async of course we already know that the migration was folded only from the reit db context so only this will be executed actually only only once so let's just give it a try we have the application up and running and now let's just jump back to data grip hit refresh so refresh we have databases but now it's like one of two i can see that i have my packet and yeah my application actually defines scheme and this scheme is called packing and within this scheme i have two tables so first is packing lists and this got id version name and localization and now we have another one which is the packing items with id name quantity is packed flag and this foreign key to packing list so it looks like we basically have the the ef core up and running and actually collaborating with our application so now it's just the matter of jumping to the last final layer which in our case would be a presentation layer and see whether this actually works as expected so whether everything every single layer is collaborating with each other so in pocket we basically are going to stick with the you know well-known asp.net core controllers of course there are different i would say alternative approaches of how you could actually create this layer responsible for handling http requests like you could use the feature uh known from i think that was asp.net core free which is their routing so something if you're i would say familiar with the good old nancy project for asp.net uh in which you basically define the endpoint and the callback that should be eventually called this is something i would say similar which of course has its drawbacks because you don't have this nice capabilities of asp.net core controllers like like data binding uh to particular to particular c-sharp objects and many other things but in general you could completely get rid of the of the controllers but yeah we'll just stick to this uh traditional approach in in this course so let me just first clean up this a little bit because i've got like weather forecast model which comes from the default project so also the controller will be something that i would like to avoid and yeah let's start with our controller so of course everything is already wired up by doing uh net new web api uh or like by doing this from the from the rider so of course we already have like ad controllers we are doing map controllers in here so it's just now the matter of adding something to our sp.net core project and this should work just just fine so i will create as you probably expect the controller called packing lists controller okay and this basically will derive from controller base so controller base okay i will also mark this as api controller and i would like to have this route so route is basically this template controller or maybe even api slash controller will be more precise okay so we've got our controller now of course we need some sort of actions for the http uh for our http requests and yeah we need to implement each individual action for both commands and queries that we have defined for for our application so let's start with the gets uh and of course for the getting i need some sort of way to yeah to get the query and execute it into in within our infrastructure right so let's say get the query called search packing lists and yeah get it and execute this particular handler so for this of course we we've created iquery dispatcher so this pattern will be responsible for this delegation and thanks to this we don't need to inject multiple query handlers for into our constructor i think that we can already do the same for commands because that should not be a big surprise so command dispatcher is only also in here let me just regenerate this because the order is incorrect okay now it's way better so http get and now this will be rather just api slash packing list slash and the identifier which is of type guide and let's implement this public async task of action result sorry action result of t where t is packing last dto just keep in mind that api project sees the infrastructure so it also sees the application and this is why i have this reference to packing list dto i will stick to this get convention without async suffix and that's basically because of the cree created action that we are going to eventually add and there is some sort of enforced convention where it comes to the name of this particular method but we'll just get to that in a minute so from route i want to get and construct automatically and this is this automatic model binding mechanism which is given by the asp.net controllers this will be automatically put into our query okay and the results is a weight and then query query dispatcher query async query and of course in here i could do something like if my result is null then i would either would like to have the 404 status code being returned so not found and if it's not null then i will just return the ok with result okay now the second method maybe let me just copy paste this so the second one will be just to get with no explicit parameters within the route but from from the query i will either expect the search phrase parameter okay so i have query and the result in this case will be integrable of packing list dtl so i need to change this also in here so innumerable of t where t is our dto and we can immediately see that we have this code being slightly duplicated so it's now the matter of whether we would like to have some sort of base class or we just want to extract this as some private method probably putting this to some sort of abstract class would be more sufficient because we might end up with multiple controllers and it makes no sense to create the private method in in each of them so maybe let's just do small refactoring base controller and basically this controller will be abstract class which will implement sorry derived from controller base and i can already clean up a little bit because this will go from here to here and in here i will create protected action result of t result and i will call this ok or not found and this of course will be to result and t result result okay and if result is null then our return not found otherwise it's okay with results now i can refactor the controller now it's using the base controller and this is rather okay or not found same goes here this check is not required anymore all right so already looks better now the uh the actions that we are called the command dispatcher so let's start with post request so hd post and this post will create our packing list so public async task of i action result and post create packing list with items okay dispatch async command and return and now created action created action okay i missed at so created action and now i need to pass the name of our method which we can call to retrieve the resource so in our case that would be this name of get and this is why yeah for some reason ryder expects me to call this get rather than get async and return the identifier of the of the resource and null because i don't want to return the whole object as the as the result so return created at action just like that and this should yeah eventually call our command handler in the application layer and we should get the uh link in the header some some some sort of you know richardson uh fourth maturity level like with the haters but not exactly actually uh underneath with the link that this newly created resource can be reached at the this particular endpoint now at this point i would like to discuss one thing regarding this this identifier being returned to the color because this is very common question when it comes to cqrs so okay once you are creating some sort of resource like our packing list with items how the heck i will inform the caller our let's say javascript application about the identifier of this newly created result and of course there are few different approaches that you could adapt so in our case as you already discovered i'm basically passing the good identifier into my command right so i am expected that the it will be actually the client's responsibility to give me this pre-generated identifier and of course the reason i they don't need to know anything about my internal database state is this assumption that the identifier will be basically the good so it's very unlikely that i will have the conflicted uh identifier for my packing lists of course someone may say at this point okay but yeah good is not very optimized for the indexing so for me it's not a it's not a way to go i need something slightly slightly different so just keep in mind that not necessarily because i know that the developers tend to think about like the the identifier is always this artificial number that we come up when it comes to you know creating the software um this is like more to me more technical concern and if you are able to find the natural key for your resources then maybe it's completely fine to omit the identifier completely i mean in our case since we at some point we had this assumption that the name needs to be unique uh for for our packing list this turned out to be more like natural key so even without knowing the identifier we could change this to let's say long and use it in the entity framework right and this would end up with the database being generated with the number identi numeric identifier and if you would like to ask for the particular resource then the implementation will be slightly different so instead of doing api packing lists let's say this grid though there will be api packing list slash the name of the list and that will be the key of my resource which would be required for getting the information about the particular packing list um of course at this point someone may say yeah but i i did my best but i didn't have any natural key natural candidate for for the key so i need to on the ones i need to create this artificially but also i would like to avoid the situation in which um yeah i basically passed the guide so a nice alternative way is uh let's say snowflake id so the general idea is that you end up with this long so basically 64 bits of for for your identifier and there are three actually four sections uh that built this particular identifier so you have one bit for the sign 41 bits for the timestamp and thanks to this you can order your packing lists uh in the chrono in the chronological time uh sorry order not the time chronological order and then you have the generator so you have 10 bits of for the generator so this will give you this uniqueness and you can and you can be pretty much ensured that you will have no no conflicts within your whole application and then you have also something for the sequence also for the indexing purposes so once you would actually have the snowflake number it's still a number it's good for the for your database purposes and it can be pre-generated somewhere in your application before you actually call your command dispatcher all right so you could do something like in here by var identifier equals and then this id generation put it into your command and yeah you would have this identifier created before you actually hit the command dispatcher i mean if this is too much then yeah just you can make more relaxed version of cqrs and return the return the result from the command because maybe uh you don't like this approach to generate the identifier in the in the api and that's totally fine if you if you want to avoid this i think at the end of the day if something works for you and this will be used only for returning the identifier you can do it but in this in this particular case i i just rely on the identifiers this grid identifiers and works just fine all right so we have the post for this packing list creation we can proceed further so i'll just copy paste this so now it's the matter of maybe put and this put will be for adding the packing items so from body actually i miss here from body so it's rather wait from body and add packing item and the end point will be probably slightly different so that's packing i need to check the identifier so it's packing list id okay so packing list identifier slash items will be more restful or rest ish and in this case i will just return the okay all right so this is the put and same goes for packing so we can do items slash name slash pack okay and the put is actually pack items three pack item okay and the last one will be related to deletion both item and list so http delete so packing list slash item slash name and this is the delete so delete uh delete call this remove remove packing item okay so remove uh so this is the first and the last one is delayed packing i think that we should make this more in more unified fashion so maybe remove is the one and also now we'll change the name of the handler okay so remove packing list this is the command and this actually will be the uh identifier but in here we have the id okay so id this is good we can also add the constraining here this is the good as well and also in here this will be good okay so two methods for getting and underneath this uses of course the query dispatcher and a few methods for maybe i'll change this to put okay so put put so two puts delete post to gets and that's yeah something that is satisfying of course delete is also required here here put put post now now it's good so let's just give it a try run the app and we should see whether this works or not so our packet api is now up and running and as you can see it's can be reached at localhost 5000 once swagger slash index html this is like default configuration that comes with this project scaffolding we have our end point so let's just start with creation of our packing list i've already put a few breakpoints on different layers so we'll see how this whole flow actually is wired up so let's just go to post try it out my list is name maybe we are traveling for five days gender is zero so this probably will be female i believe um localization i'll just do or so poland doesn't really matter because underneath we are relying on this damp weather service but once i will hit execute we should see how this works so we have our packing lists controller now we can proceed further we have our post method our command looks as follows so it's kind of hard i see okay let's just do it like here so we have the days we have the gender which is sorry in this case that was actually mail identifier localization which contains both city and country and the name is my list all right let's move further now we are within the repository so repository is constructed actually as you can see this is just the um the constructor and the reason for that is that probably the types are being resolved right now and indeed you can see that command dispatcher was asking for required service in our case that was the command handler and the command handler of course needed the repository to be resolved so in this case we can see that this actually is our create packing list with items handler and we are calling our handleasync method so this looks good so far now we are checking the existence of our list and if this my list already exists somewhere we should have the exception being thrown so at this point there is no exception and now we are calling our damp weather service for the for the uh temperature of course we know that the underneath there is like uh just random so yeah the generated number is actually 15. now we can move to our uh more like domain part of this execution which we'll call our factory so factory gets this data and creates this policy data in here now we need to filter the policies that are applicable for our execution so what are the chosen policies so we should have at least two so first is the basic policy because the predicate was as you remember like true so this always needs to be applied and also male gender uh policy and the reason for that is that we have only two is that we have 15 degrees right so the temperature is 15 so this is neither suitable for the high temperature policy because it's lower than 25 degrees but at the same time is is too hot for this low temperature policy so that was just the i would say luck that we had in here and okay we can move further so let's just jump to our factory so this is what we have now it's just a matter of generating the items putting this into our packing list and eventually this packing list should be returned to with as you can see 14 items which are generated for us and this should be returned to our command handler and the command handler eventually called our repository and async method to persist this into our postgres so once i hit okay we should see that we actually have the 201 created and this actually already gives us this nice link with the location so our newly created packing list is available at api slash packing list and this is the identifier of our packing list of course we can confirm this confirm this also on the database level so packing list is indeed in here we also have the packing items being being inserted into our parking items so let's now focus on the read site so for this purpose i will just add few more break points so get in here and also [Music] get in here okay so now let's just jump back grab the identifier which is here and get this by identifier identifier should be this execute all right and i'm getting the 404 from the swagger which honestly i don't know why so for this purpose i will just use the postman for getting our packing list so one more tool that we can use for uh fetching the data from our api i'll just click send and this time it apparently works so once again we are moving our packing list controller but now this time we are using query dispatcher query that contains the identifier of our packing list now as we can see we are within the infrastructure layer and we can construct the whole and the whole response so we are including the items with this particular identifier we of course then producing the response as a dto with no tracking singular default async let's click continue and in here indeed we can see that we have our list with the items being also included so it looks like our api is working probably the rest of the of the end points should work just fine because the whole mechanism is is the same i mean from the technical point of view of how we wired this all together this should work of course maybe i did some typo or maybe some other like you know implementation detail but when it comes to the um i would say architecture uh perspective this should work just fine because yeah the the whole execution process is common for both queries and and the and all the commands so i would say that there are only two things that actually remain when it comes to the overall capabilities of our api and this is more like infrastructure thing first is the ability to in some way handle the errors because at this point if i will just jump back to our post and i will try to create the list with the same name so that was like my list i believe when i click execute once i once i will get to the to this i've got this exists async and in this case as you can see my execution is aborted and that's because yeah indeed i have the packing list with the same name and also this should be present in here so i've got 500 internal server error and i've got this not so pretty not so pretty calls pretty call stack being displayed so i would rather like to create some sort of response which would only contain this nice this nice message that packing list with name my list already exists and maybe some sort of error code for the translation purposes yeah but anything other than that should be pretty much omitted and also maybe uh we could think about replacing the 500 with 400 so bad request would be more more sufficient for for our application or domain exceptions so let's jump into the code and modify it a little bit okay so the general idea behind aero handling is very simple i will just create somewhere in here within our shirt package i will create the asp.net core middleware which will catch the possible exceptions being front from you know domain application or the infrastructure and based on the type will perform some action or not and that's i would say whole magic so let me just create directory called exceptions and in here i will define exception [Music] middleware so this will be internal sealed exception middleware which implements high middleware and in here um if you're familiar with the with this asp.net capability you probably know that we have an access to http re context which gives us an access actually to both request and response and we also have this request delegate which is um i would say next step within the whole http request execution so just to briefly discuss this particular parameter uh if we jump back to our let's say entry point of our application so to start up cs in uh packet api so our asp.net application we have two methods so subscribe sorry configure services which is just the configuration for our dependency injection container and basically in here the order does not matter at all i mean we are just adding something some some registration to the um to the container while in here within the configure method we are defining the whole execution pipeline of http request and in here the whole ordering of this particular method invocation actually matters so this is how our execution pipeline look like so we have like first we are using the https redirection we are using routing and the authorization and at the very end we have the controllers being mapped so these are step this is first step second third fourth etc so in our case we would like to do the following like somewhere in here i will just do use error handling and the reason i'm putting this at the very very beginning in here is that i would like to i would like my handler to catch any possible exception that comes from my application so basically this could be either here or or here but the crucial part is that this needs to be called before use end points and this map controllers because the controller will eventually call our application or infrastructure when it comes to queries and these these are two possible i would say places in which i can throw my exception or i can also think about another type of exceptions that are not created by myself but maybe they come from ef core like like concurrency exception or maybe some configuration exception that comes from different types of infrastructural pieces that i'm using within my application so i would like to catch any sort of exception that might occur within my application and yeah react to um to this thing so in our case since i'm going to let's say leave it as it is so this will be one of the first steps being defined for the http execution in here the next refers to next step with this pipeline so this might be like authorization or this https redirection but eventually this next underneath calls another next etc so we have this chain uh from this middleware point of view the crucial thing is that this next eventually we'll call our controllers which means that i need to just wrap it into try block and yeah any sort of exception being thrown should be catched in should be caught sorry in here so what i'm actually going to do is the following i'm interested only in the packet exception so this is the one that we defined at the very very beginning and yeah since this is the custom exception i don't want to throw re-throw this exception further i would rather create the nice http response for my color so context dot response dot and i will first set the status code so for now it's like hard coded information that this will be always bad requests but of course we could think about more maybe component which will decide which status code should be returned depending maybe on the on the payload of this exception or something else but let's just keep it simple for now so response dot headers i would like to add the header so content type so content type will be application json because i want to return to json so application json okay now i would like to create the error code so not only i will use the message that comes within my exception but i would like also to create some sort of very simple error code let's say based on the type of my exception so let's say let me just give you an example like we have domain exception so like here empty packing list id exception i would like to create some sort of error code which would look like empty packing list id something like this without the exception word so that would be snake case text which basically takes the uh name of this exception type and transforms this into a nice uh error code which could be eventually used on the let's say javascript application for picking the error message based on the translation settings or something else so in our example uh of course we need some sort of method for accepting the string and making this more like underscore case so let me just copy paste the method that i for sure didn't get from the stack and we can now use it in the following scenario so var error code equals and then to underscore case and i need to get my exception get type dot name but i also need to replace the word exception with exception with string empty so i hopefully this is clear i take the name of the type i'm removing the exception and i'm changing this from pascal case to like snake case and now i can make my json so i'm calling json serializer from system text json then serialize and i'll just use anonymous object with error code and with ex dot message and await context i think that error code should actually be used like this because otherwise i would have one starting with the capital m and this would start with the uh non-capital e so await context dot response dot write async and now we have our json and that's it so of course the question remains what we gonna to do with the other types of messages let's say invalid operation exception or something that could come from the uh from the let's say ef core or something yeah we basically don't care i mean this will be returned as a 500 with this stuck uh with this call stack of course we could add this but you get the general idea so it makes no sense to add now the error handling for every possible exception that could be thrown uh within our application so now it's just the matter of uh adding this middleware somehow so in this particular case i will just get back to shirt and we have this at shirt method already so let me just add another one so services that's scoped at scoped and exception middleware and we also need now another method so public static eye application builder use chart and this will be called an eye application builder app okay and use middleware exception middleware and return app okay so now let's just copy this and we can again jump back to error handling so in here i could maybe do this in here after the http uh s redirection the key point is that this needs to be before these endpoints and yeah this should be working just fine so let's give it a try the whole application should be up and running in just a few seconds and once we have it let's just try to create once again the list with duplicated name execute and we have four hundred so bad request with the nice response which says that packing list with name already exists and we have also our error code so yeah this is now way better than it it used to be so the second and actually the last thing related to the infrastructure and this is also quite common question regarding the clean architecture itself it's like yeah with with this approach it's it's very i would say in in here you have very clear boundaries between what's uh belongs to application domain and the infrastructure but what about this stuff like logging i mean logging is very common and you probably want to add the logging eventually at some point to your application and yeah does it mean that i should add my login to application and in here like to command handler or is there any other way to do this in more i would say robust way so of course in this case it pretty much depends i would rather avoid injecting the logger into the command handlers and that it's only because i'm i'm not a big fan of of too much locks because it obfuscates the code natalie for me and it's becomes very unclear of course this depends on the type of the code so if you are creating a library the the login is very helpful and every everything related to infrastructure is very helpful so maybe for let's say shared our app initializer somewhere in here using the logger would would be would be a proper usage i mean i would like to see maybe on the application bootstrap face i would like to see information that okay i've discovered two db contexts and now i'm executing the migrate async method on each of them so in this case it's it's way better than having just no information at all but yeah for the application every single time i'm creating something and maybe i would i would like to keep this application layer more more like clean and i would like to avoid the situation in which logging is defined together with my process logic it's just something that ideally would should be treated completely separately so how can we add the logging without actually adding the logging to our handlers at the very beginning of the implementation uh once we actually i think jumped into the application uh layer we've added the the package called scratter so at that time i mentioned this that this crater has two capabilities that are added to asp.net uh core dependency injection container so one of them was the scanning ability which we used for automatic scanning of command and query handlers and the second capability that we are going to use right now is the ability to decorate the classes that are basically registered in our ios in our dependency injection container so a good example could be the logging in this particular case so i will within the infrastructure because once again it's more like cross-cutting concern so i this is why i'm defining this within the logging i will create the directory called logging and the class which will be called let's say logging command handler decorator all right and of course internal sealed just to keep this not accessible to anyone else and the idea here is very simple uh the whole pattern is based on the assumption that the decorator will wrap the natural behavior this origin behavior of uh yeah the thing that it decorates so in our case as the name already says we want to decorate the behavior of command handler we want to enrich its its uh its capabilities with the ability to lock some sort of useful information and uh to make it work the decorator will implement the same interface that the component that we would like to decorate so to make it more clear we want to implement here i command handler of t and notice that i'm implementing this as the like open generic i don't you want to specify any particular uh any particular type it will be just applied to any sort of command handler that will resolve in runtime within our application so of course we need to fulfill the same same [Music] constraints so this needs to be first the reference type and needs to implement i command interface and now i can implement this and the idea is very simple in here i will create the i command handler of the command so this is our command handler and i will also pass i logger which comes from asp.net core once again of t where t is logging command handler decorator of the command logger and this those will be injected so what it means is that where like whenever our query dispatcher sorry command dispatcher in this case will say okay give me i command of t the actual the actual type that will be resolved by the container is not gonna be the handler itself but rather decorator with this enriched behavior which inside will have the original command handler being injected so we can think about this as some sort of um like sort of middleware but on the ilc level so now i can without changing the behavior of my original command handler i can wrap the whole execution of of this handler into some sort of more uh advanced thing and the cool thing about the decorators is that i can apply multiple decorators on the same concept so each of the decorator could enrich my execution with some different uh with some different behavioral so one could be dedicated for logging but i could also think about decorator for maybe creating a metrics or some you know other stuff related to other cross-cutting concerns so in this case i will just add this login capability to my handler execution so the whole thing will be the following i will create command type variable and that will be just command.goodtype.name in here i will just do try catch and in here let's just type something so maybe log information log information and here started processing and this will be our command type command okay now i want to call my handler so first i will write this message then i want to call my handler passing the command and let's say after i finish i will do finished processing this command and once i will have some sort of exception being from because maybe i've got the exception on the domain or the application layer i will just do here lock like error and the information that failed to process and then command type command and the crucial part is that i need to throw this exception further because if i will swallow the exception here then yeah i will never reach my exception middleware that will eventually return the http response so it's critical for me to always remember that the point in my and i would say the place in my application in which i am basically responsible for actual handling with the exception is my exception middleware while in here i am only enriching my uh whole execution with some additional logging but then i need to re-throw this further and that's pretty much it when it comes to when it comes to [Music] whole decoration stuff of course at this point i need to somehow uh explicitly register my decorator because yeah it's not that smart i would say and of course that would be quite hard to to come up with some sort of uh automatic registration of my decorators so somewhere in here with my ad infrastructure i will do the following services dot try decorate and in here i need to pass of course the component that i would like to decorate and then the type of the actual decorator so i will use the non-generic versions since my i want to register both uh the creator and the co and the command handler as the opengeneric so i want to decorate this type with this implementation this okay so let me just run this up and put few additional break points so one in the decorator itself okay one in the decorator and okay another one in the actual handler so here but this one so the handler and that should be maybe the last one in the in the dispatcher okay so now i can just get back to the swagger call the post with my list execute and let's see what happens so in memory command despatcher asks for i command of t but in in as you can see we are not getting the command handler directly but rather logging command handler decorator of t so in our case this t is of course create packing list with items now once we'll basically call handle async we're not gonna call the process logic directly but first we will enrich our whole execution with the logging information at this point once we'll print this information we want to call the actual handler and now it's this whole part related to the process logic we already know that this will gives us an exception so i need to be prepared for it so in a catch i can lock the information that yeah we failed to process the command of this particular type so we in here we should see the information and we need to throw this particular exceptions further for our exception middleware just to create nice a response with four hundred so we can see fail and we can see that fail to process create packing list with items comment of course we could log also the reason maybe the message of this exception but yeah for us it doesn't really matter at that point it's rather a quite simple change and now i could also see this 400 in here but the handler handler's behavior got enriched with the logging capability without actually changing the the implementation of course someone may say okay but what happens if i would like to lock something very specific to one particular handler yeah in this case i mean it's it's quite hard to to come up with the decorator with the decorator itself because the decorator can only gives you can only gives you the logging at the very beginning and the end of the handle async and not let's say somewhere in here but in most cases i would say i find i find found it useful and this is my preferable way of of dealing with the logging uh once i adapt the clean architecture all right so let's just briefly discuss the unit testing because this is the level on which we're going to focus within the packet project basically if you would ask anyone about the purpose of doing the unit testing there's al always this one keyword which is the isolation so the idea about the whole unit testing is that you basically have this unit whatever is whatever you uh you know defined it and the whole idea is that you want to give this object an isolation from the outside of the word so by doing this you are preventing the situation in which the failure of the external component basically breaks the test of the cont of the component that you're actually testing and i would say that this is partially true um i mean there are two different schools where it comes to the testing itself at least two popular i know so first is the so-called london school or the old or the moki school so basically in this case you are using the actual let's say marks or stops or other test doubles to isolate your unit which in most cases is basically a class from the outside of the of the of the word so let's imagine about the command handler which has few dependencies being injected into the constructor like the repository like maybe some domain service etc so instead of giving you the actual implementations which could be implemented wrong you're basically mocking all of the dependencies and then you're giving the mox particular behavior adjusted to each of the individual scenario and that's pretty much how it works and thanks to this you can go through every single let's say flow that you have within your command handler and yeah and see whether this particular uh let's say implementation actually is valid or not i mean there are a few issues that i have personally with this approach and you'll see this once we'll jump into the code but uh this is basically this london so-called london school the opposite i would say team uh is called chicago or detroit school and basically this is more um i would say traditional approach in which you're actually giving the the uh the actual implementations when it comes to uh your dependencies so i would not create the mods but rather the actual implementations of course as long as you have as long as as it's still like just the in unit test but not the integration test so let's say that i'd rather not give you the actual database connection but let's say that you have the factory being injected to your controller or to your command handler then yeah i would give you an actual implementation that comes from the domain and i would just as a unit i would treat this particular behavior that i'm trying to i'm trying to catch within each scenario and that could be more than just one class in general and in this particular course we are going to follow the london school since uh i think that's especially for the beginners it's easier and what is has the advantages and disadvantages is less painful when it comes to creating the the arrange phase which i'm going to cover in just a second but basically yeah since you're creating the mock using some sort of library it's rather straightforward when you have the class which has a lot of dependencies yeah for each assuming that you would follow the the detroit school uh yeah you would need to create every single dependency manually using let's say new operator and you just need to remember that those components might also have its dependencies so at the end of the day you might end up with multiple like you know thousands of of the dependencies that needs to be created first to actually provide the proper uh proper components to to the class that you actually wanted to test so there are pros of cons of both a pro both approaches i'm more into the marquis school but this actually i would say in most cases applies only to the application level because that's where you have the abstractions on top of in most cases like i o bound operations uh when it comes to domain it's rather straightforward and in many cases as you will see it's not even needed to think about mock stops or or any test uh other test doubles um and yeah so you're going to see how this london approach will look like and of course we are going to structure each of the tests into like three phases so we have like triple a or um what it means is of course arrange act assert a range is the phase in which we're trying to prepare the whole environment for a particular test scenario uh so in this case you might let's say add the behavior expected behavior to your marks or maybe you want to prepare the uh i don't know the the the command itself that is going to be the input for the command header or anything else uh the act is the actual essence of the test so the behavior that you are that is under the testing in particular scenario and the assert is nothing more but validating whether the result is just matching the ex your expectations so those three steps will be of course implemented in each of the scenarios and yeah this is basically how we're going to uh to tackle this and we're going to see the uni example unit tests both on the domain level so you will immediately see how easy actually it is because of this lack of the i o operations in there because when you think about this it's like my aggregate has the input some sort of like let's say value object entity whatever and it has the expected output which in our case would be the the domain event and that's pretty much it it's like just giving an input and expecting the actual output uh as a result and that's pretty much it i mean it's it's very very straightforward for the command handler it's more about those mocks and adding the particular behavior to them but it's still since the whole is more granular it's like the representation of particular use case it's rather straightforward and and there should be no big big issues with with uh covering and adding the the tests to each other of the individual uh handlers so this is going to be the only level that we're going to cover i'll probably uh we'll probably as the mentors create like different courses mini courses or materials regular materials on the youtube about the testing itself i would love to cover the ddd and behavior driven development but yeah this is that's another topic and just let's just jump into the code and see the actual implementation all right so let's just jump into our unit testing and as you can see i i already have packet unit test project uh typically i would probably split this uh into two separated projects so one would be for the domain one will be for the application but i just want to make to keep those things simple uh one thing though is that as i mentioned i'm gonna follow the mocking schools of the london school and for this purpose i added one library called and substitute i also added the uh should lee and basically should is library with for the fluent assertions so the a third part uh phase within the testing should be more expressive when it comes to the expected result so i think that without further ado we can just jump into the uh first test scenarios and i think that you immediately see the benefits of the of the clean architecture itself so let's start with the domains is once again it's the most important layer so in here i will just create the domain directory and i will just add example class when it comes to naming convention uh within the testing i'm going to [Music] yeah the the the naming conventions will be slightly different and casing could be also slightly slightly different for the test classes i will stick to the pascal case so let's say that i would like to add some testing for my packing list aggregate of course this is once again your choice whether you want to let's say dedicate one testing class for let's say one method or maybe one testing class would encapsulate every behavior that you have within your aggregate in a in in this case once again because i want to keep it rather simple i will just create something like packing list tests so that would basically cover all my uh public apis exposed from from the aggregate but you can just make it more granular and maybe dedicate it to and separate it to one dedicated method so packing list tests and yeah i think that we can add first uh scenario um so let's start with the fact attribute so this one comes from the x unit so this will just indicate that this actually is executed executable test and since the domain itself is not dependent on the i o i can make it synchronous so that would be rather a public void and now it comes to the name of this scenario itself and in here i'm go i'm gonna use some sort of i would say snake case but with the pascal casing i'm not quite sure whether this has its name i'm probably probably there is there is a name but the reason i'm not gonna follow the pascal case itself is very simple uh usually i i like to the methods to be more very expressive are very detailed uh what expected what behavior i expected in particular case so obviously this implies quite longish name and pascal case to me basically doesn't work i mean it's really hard to to read it um to read something in a pascal case when you have like six seven eight uh words within the uh name of the method so i'm using this hybrid uh snake case and pascal case approach and to me it works just just fine so um yeah let's uh start with let's just jump maybe to the domain and to this packet packing list and we have metals like this so adding an item which accepts the uh packing item and first we are checking whether the item with the particular name already exists and if actually this happens then we are forbid an exception so let's as an example uh let's test this method so we can split this into two separated scenarios so first will be failure so checking whether this exception actually gets thrown once we have the duplicate based on the name and the other one would be this successful path which would add the items to collection and would add the domain even to our aggregate route so let's start with this with this first approach so the name i'm going to create will be first name of the method so add item then froze then i would just copy paste the whole exception because as i mentioned i want to be quite detailed so once this actually gets let's say uh gets failing i will immediately know what actually happens um so froze packing items already exists exception when and then there is item with the same name maybe already ready item with the same name all right so just like this and i need to just correct this so name is kind of longish but at least i know immediately what behavior i do expect so first things first i would like to create the packing list aggregate which is kind of obvious so maybe for this purpose i will create the method which will help me to create this packing list er in every single scenario because maybe i don't want to make this like uh this codes are duplicated i would rather want to extract this somehow so get list okay and now i would like to create the packing list the issue though is that of course the packing list itself has private or internal constructor so i'm not allowed to actually construct this of course if you don't want to complicate your life even more yeah you can make this public and just relax this assumption that this class is fully hermetic and it's can be constructed only via the factory yeah but in in my case i would like to just keep it keep it uh rather private or internal so of course the only way to create this packing list is through the factory so in this case i'm going to create another [Music] field in this case so that'll be private read-only ipacking list factory okay and i'm going to initialize the constructor and i'm just going to manually create the factory and the reason i put both constructor and private field at the very end of the class is that when it comes to unit testing and testing in general in most cases the uh like everything which is related to fields and and constructor is rather the arrange arrange phase so preparing the whole test scenario to execute um so to me the arranged part is not that crucial to me the act is the phase that i want to be focused on and of course the the assert because in there i met i make all the verification but the arrange itself and preparing the whole environment for the for the test execution is rather not very important so i usually when it comes to unit testing this stuff actually gets gets at the very very bottom of the class and usually i also i put this into the region like a range and that explicitly will tell you that now this is just the arrange face um so in here the factory gets instantiated um just by using new operators so new list uh sorry packet list factory and of course in here we are expecting the policies but in our case the policies are not very important right now i mean we would probably create the different domain uh sorry different unit tests for the factory itself so i don't care right now i'm just passing the innumerable empty to just have this sort of policy being resolved but i don't care that much about the about the particular policies that we'll have within this factory i just want to create this packing place i aggregate somehow so this is it and now i can implement my packing list so i will use second overload actually so packing list gets created by the factory and the we had two methods so this is the one that we use within the command so create with default items but we also created but actually haven't used this this one which is just create and create the assumption and idea behind this is that we'll basically have no generated no generated [Music] items are added in here we'll just basically create the empty list with no default items at all so in here i will just pass the some sort of guide name of the list and then the localization which is created using this static factory so let's say like warsaw poland and this of course needs to be finished that way and then just to be sure that there are no events i will do packing place dot clear events and now i can return it all right so first scenario we want to check whether uh this exception is from and with actually this actually can be moved to my arrange i think with no issue okay so in here first of course i would like to create the packing list itself so i'll just call get backing placed and now i want to add the i i need to first create this duplicate right so i will just do let's say that we are still within the arrange so i usually don't do this but for now just to make it clear this is still a range and during the arrange i would like to add the item and this item is going to be called let's say item one with quantity one okay so that's my arrange now the most important stuff which is act so i want to make sure that once i do the exactly same thing so i want to add the uh item with the same name i will get an exception and of course the different sort of ways of actually verifying but for the x unit the easiest one is to use the record so not the record which is the c sharp record but rather the record static class that comes from the x unit so var exception equals record and then we have to overload so we have exception and exception async i will just go for the first one and in here i'll just put the code that needs to be verified so i want to make sure that this actually produces this exception and i want to make sure that this exception is actually not null and for this purpose i'm gonna use this extension method from the should lee so should not be null okay and the second one is that this exception should be of type and here i will just copy paste this from the name of the method so this should be of type packing item already exists exception okay so let's just run it and immediately we should see the yeah the test is actually green so yeah the method underneath works as we as we expected we cannot add the item with the same with the same name so this works just fine now the second test will cover this scenario so we want to make sure that actually yeah the items gets [Music] gets added of course the issue with this approach is that since now we have yeah everything in here is private so the lists with the items is list with the the items is also private which means that yeah there's no easy way of checking whether this actually gets added to the to the collection the only i would say assertion that we can make is to rely on the domain events that we have within so the second test will basically check whether the aggregate now will contain this packing item added event and if so then we'll just yeah believe that actually that happened because uh semantically this means that this operation actually succeeded of course yeah there might be some sort of questions like okay but this is just the event but what what happens if someone will basically throw this line away uh in this case your test will still pass but the item actually isn't isn't being added i mean i know in this case if you really don't trust i mean yourself or the other developers which is perfectly fine uh you can just make this maybe public and [Music] and you will just make the make the assertion or maybe create just public uh i innumerable which would expose this for their reading purposes only and in this case you would have this uh you would be certain that this actually happened but once again it's it's it's either choosing the being fully hermetic and encapsulating the implementation details and relying on the on the output of our aggregate as some sort of single source of truth like if this happens the assumption is that this definitely happened uh or if you don't want to complicate or other ads you know you don't want to add more boilerplate to your code then you can basically throw those domain events away and just uh make everything like being rather public uh properties with getters and private setters and this would like in this case and that would in this case the assertion can be done directly on the properties rather than on the domain events so i think that this now should be should be clear so the second scenario uh is going to be the following um let me just create the fact and another method okay and the whole test is going to be called add items sorry item and then adds and then packing item added i believe so this one event or maybe domain event on success okay so um this few lines i think there can be actually they can be actually copied this one is not needed anymore because i don't want to make the uh this actually to to be uh not now i would rather have this to be null so i can make already the assumption that exception in this case should be now because i don't expect anything to be thrown from the item method so should be null okay and then i can check whether actually i have the events in my collection because uh actually the events are exposed from the aggregate route as the public property so i can do something like uh packing list then events as you can see innumerable of i domain event and then count and should be one so i'm expecting in this case that i will have exactly one i can of course check the type so i could do something like var and then event equals packing clays dot events dot first of default and let's say that s packing list added actually this one [Music] so this one okay and of course i need to check because i'm using die like s operator in this case so i need to verify whether event that actually that should not be now should not be now because if i would have this assumption uh this assertion actually may pass but if for some reason the domain event which is added to my events collection is of different type rather than the packing items added then this whole line will return me the null right i mean the object is there but once i'm trying to cast these two packing items at it i will get them now so this is why i'm doing this uh like like in this particular case i'm using the should not be now of course if you would like to do this differently you could do something like you could remove it and do should be of type and in here packing list add it uh sorry packing item edit okay so that would also work but the reason that i i wanted to use the the s operator was that now of course if i will make the run this should work so let me just yeah this is already green but maybe you would like also to check the payload of this message and in this case if you if you have the event uh so the event in in this case is as you can see i domain event so in order to actually access let's say in the name property that we have within it i would need to do something like [Music] packing list uh sorry parking item at it and then event and then the packing item and the name and here let's say should be that was like item one okay so it's not very pretty in this case i think that like this ass packing item added and should not be null is is better but it's of course rather your choice what actually suits you more so as you can see still still green maybe i'll just get this to the previous one okay so should not b should not be null okay all right and this is not necessary anymore you can just make sure that this still works okay and yeah of course i would rather recommend to put not to put too much uh assertions within one test i mean in this case all of them are more or less related to the fact that i have like one domain event within my aggregate but it's it's better to have like more granular scenarios which will have fewer uh assertions rather than having one big ass method with with that like you know dozens of uh assertions at once so i forgot to put of course the assert so that's arrange act assert and of course in here it's like arrange act and here starts the assert so i think that this will give you the flavor of how we can actually create those scenarios because yeah if you would go to packing list it just every single method would do pretty much the same thing so in here i'm let's say pack item i'm getting the item first and in here i'm checking whether this item already is actually in the list if it's not then i'm referring the exception so it's just a matter of going through all the cases and yeah either checking whether we front some sort of domain exception or not and etc and verifying of the on the aggregate level it's rather verifying whether you have the exception or whether you have the domain event added to your to your list so it makes no sense to go through every single method that we have within because the methodology would be exactly um would be exactly the same and uh of course at this point uh there might be also questions regarding the let's say get item method so how do we actually test it um with the everything which is private or or internal i mean i think that by by design you should not test this somehow of course there are some sort of hacks for the internals uh in the c sharp so you can put this attribute internals visible too and you could access it from the unit test project but for me if something was a rather internal or private that was done on purpose and the yeah you can make it even more i would say granular or you could test specific specific method and make sure that this works but if someone decided to put this as internal this means that from the outside is rather the implementation detail and the issue is that once this detail actually gets changed your test for this method breaks immediately so we need to repair the test and put the new code also and yeah this is something that i'm i'm not very [Music] i would rather avoid such uh such testing in this particular case and uh yeah i think that's the this is just for you only test what is public and of course eventually you will you will i would say indirectly test also uh private and internal methods which are used to to call your which are used within your public api but it rather makes no sense to to test it also separately in different scenarios um okay so when it comes to domain i think that this is rather straightforward and you get the idea uh how this actually can be done let's just move to the very last topic which would be the application uh i mean unit test on the application level which honestly i'm i mean i used to be a good maybe let's put it this way i used to do that quite often when it comes to [Music] code coverage and and in general writing the unique tests but i found that with the london school with this mocking approach at some point i'm not quite sure whether this makes that much sense i mean the domain of course itself is crucial and since there is no i mean the mocking within the domain is very limited so you're basically playing on the actual objects um while with the mocking school on the other hand if you will take specific command handlers let's say you might end up with the code that actually just yeah it's more about the setup of every single mock rather than verifying the crucial functionality and the issue if that i have personally with this approach is that at some point you're basically testing too low so once again i'm i'm let's say adding something which is completely not related to the process logic itself let's say that i'm adding like i logger to my command handler which i shouldn't do because ideally you could do the approach that um that we we followed so putting this into the decorator but let's say that you added you decided to add the logger to your command handler and now your tests immediately are broken because it doesn't even compile because you added new parameter to your constructor and now you're missing it and yeah ideally you just need to go to the tests and check and add this one parameter to the constructor to make this uh to make this compile uh once again so at this point your tests were broken because you added something which is not even a functional requirement and this could be a symptom of testing too too low and especially if you are following the the london school you i think that you will see immediately uh what i yeah what i don't like about this particular approach uh at some point so let's just add the last directory in this course so application and i'm going to take the this command handler so creating packing list with items so let's just copy uh copy the name and i will just do tests so the for the command handlers the command handlers are uh what i like also about the cqrs is that for for the testing it's way easier way granular because obviously you're going to end up with one test class for one command handler and in this case i follow slightly different approach um rather than this one which is kind of simplified i mean in the real life i would probably put every method into different class but for the command handler in here it's like uh you would you're kind of forced to to do this uh because yeah the command has just one method so it's it's kind of different story so in here uh i'm gonna to do slightly a different thing that uh i usually do so at the very beginning of my class i would like to put a class sorry method called act so explicitly i will just say that this is the most important method this is what i'm actually testing and yeah if you want to read this code the very first thing which you already see is the act phase so what i'm actually executing in this particular class so in our case we are going to execute the command handler obviously so first we need to create it so once again i will just create the region so region arrange and in here in the constructor i need few things actually because the command handler accepts like four parameters so first let's create the private field for our command handler so i command handler of create packing lists with items so let me just do it like this so that's command handler okay and besides we need a repository so i packing list repository we also need the weather api service or the weber service so weather service yeah weather service okay we also need private read-only uh the read service for this exist async method so i packingly street service okay and the factory that comes from the domain so i list factory okay all right so now since the command handler is the only one that is going to be created using the new keyword the rest of the field is going to be created by the n substitute method so substitute that for and in the generic parameter i'm just passing like in this case i packing list repository and this is already assigned to our field and i'm going to do exactly same thing with the rest of the uh with the rest of the stuff so in here that's kind of kind of weird but just okay uh so weather service in here we'll have this so let's read service and in here we'll have the factory and the factory okay so i'll now have four mocks and the command handler can be now instantiated using the new keyword and i'm passing like repository factory read service weather weather service so repository uh read service weather service uh sorry in the factory as a second parameter okay okay so that's it and now this is the end of my arrange and the act is actually the command that i'm going to pass and this calls our command handler handle async command so yeah we'll the the test will be even more uh clear so everything that will be before the act is actually arranged obviously and everything that happens after this act will be assert so even if someone would be new to the test uh he would immediately knows the the idea how this actually [Music] is structured so once again in this case i'm not gonna do public uh void but rather async task because in this case yeah the handle async itself is is uh asynchronous so we need to make also the test scenario synchronous so if we would uh jump into the code there are a few things and i think that we'll end up with three different tests so first scenario is that exists by name async returns the true so this means that we have the duplicates in the database and we need to throw this packing list already exist exception the second one is that the weather api returns the null weather object dtr so in this case we are going to throw this missing localization uh weather exception and the third one is uh this scenario in which we actually persist the packing list using the repository so yeah we'll have like really nice isolation because every of those dependencies are not be directly constructed they are rather like the mocks on which we can add and model the whole behavior and control the whole flow but yeah this will have also it's it's its cost which you're going to see in just a minute so public async task and first let's focus on this uh on this read service failure so handle async because this is the method of of the of the handler froze and then let's just stick to this convention so froze packing list already exists exception when list with same name already exists okay okay and first let's create a command so the command will be new and then create parking list with new items and in here i'll just put some random stuff like good my list for now it's i don't care that much about the payload so like 10 gender female and localization for now it could be like default right and now i need to uh explicitly program my read service to re to ensure that this actually the the method that is used within my command handler returns the true which triggers the whole exception flow so i'm going to do this by using like read service and then which method is i'm interested in actually i have one so this must be exist by name async and in here i'm saying that for the input like command dot name i want this to return something so returns and in this case i want to return the true so now if i will receive like my list the expected results should be true for the rest it should be still false and then once again exception and you already know the the whole flow so in this case i'm going to use the exception async so exception async and then in this case i'm going to call my act so we are going to perform the act phase and in here exception should not be null and of course i need to await this because this returns the task so it's always not null and the second thing exception should be of type and should be of type packing list already exists exception okay yeah let's run it and the result is yeah it actually succeeded so cool let's just move forward so we have another exception that might be thrown so assuming that this will return false we we are calling our weather service and we are expecting the weather to be returned returned so let's just create another example so and once again that's going to be public async task and in this case i'm going to call this handle async froze froze and this is missing localization weather exception okay and when weather is not returned from service something like this uh okay i'm not quite sure why i know that is slightly longer than 80 characters but yeah we should be we should be fine so um let me just copy paste the command or probably i should extract this to some method but i think that it's not the most important stuff right now and localization is going to be needed so for the even though i think it's actually doesn't uh our current implementation doesn't really care about the input but yeah i'll just just pretend that we're not doing like crappy code so warsaw poland and now i can take also this one so i need to explicitly tell that now this exists by name async will return false i mean uh it's also worth mentioning that uh if i would do something like this so just completely omit this code if i don't program and don't put the behavior to my marks the returned value is going to be the default so for the boolean the default value is false of course but yeah it's better i think to be more explicit and just to explicitly tell maybe for some other developers that this should we expect this to return the false so we can process further and of course we need also to add the behavior to our weather service so whether service that get order async for let's say we can use another type that comes from the and substitute so arc dot for any type of localization and we want to return on default let's say of weather dto which in this case is of course going to be the null okay so this is like arrange now the act actually we can do something like this so copy paste so of course this is now just a matter of different exception type and because we still expect this to to blow okay so we have two different scenarios and now the successful one and the successful one we can call once again i will just add this fact so public ace task and in this case handle async persist or maybe calls because we are not unsure about the persistence so handle async calls repository on success okay in this case i will just uh i need to take a few a few lines of code from the previous one so you can already see that definitely this should be extracted somehow so once again for this particular case we of course that needs to be this needs to return the false because otherwise would have this scenario this in this particular case now needs to return something more rather than the default for the weather dto so default is now not an option for us so let's just return anything like weather dto 12 it's not that very important and now we also need to add the behavior to the factory because factory dot create with default items needs to return something so this will be rather saying that for for the particular parameters we expect some sort of message gender then temperature it's get okay i don't want to extra create now so i'll just use this shortcut so i don't care about what temperature but i'm expecting this to be any type of object which basically is the temperature may be same for the localization [Music] and i'm expecting this to return yeah in this case i will just do a default of packing list so this actually will return me the null but it's not the case uh of course the issue is that um in this particular case i would like to return the some sort of packing place but packing list of course as as we already know has this um this constructor set to private and internal so once again it's either i will create the some sort of other way to to construct this object like using reflection which is like i don't think it's very performant and fast in terms of unit testing and it's ugly looking like some sort of instance activator uh the other option would be basically to set it to public or one let's say this one could be set to public and we don't care and the third option would be to actually use the implementation of the factory with the create and use it in here but we would have the word situation in which we are actually trying to create the mock using the actual implementation underneath and this is exactly what i'm te what i'm what i mean by using the mocks in particular cases and especially if the flow of the command handler is very complicated so we end up with adding a lot of code which is actually not very related to the whole flow and yet assuming that the order of our command handler will be changed let's say that if i will jump into let's say that for some reason i i need now to check the weather first and then the localization is and and then the existence of the name is is now verified in this particular case we might have a we might have an issue because i think that in this case if i will do something like this so whether okay in this case we need the localization as well so like here okay so let's just run those two yeah and in here in my tests the packing place already exists exception uh actually yeah we expected the the exception to be of type parking list already exists exception but actually we had no reference exception so yeah the question is that whether this rearrangement made any significant change to the overall result because we wanted to have the packing list which gets persisted at the very end i would say no i mean of course from the up the performance performance wise this could be i'm i mean pretty much depends whether this is slow call or not or whether we are paying for this call uh so maybe this is why we would like to have this after checking the existence because if we are going to throw the exception anyway this makes no sense to call paid api but yeah at the end of the day we just did small changed and because of that the whole the whole mocking you know behavior was actually programmed wrong and yeah this is i would say one of the biggest disadvantages of following the london school rather than the chicago in which you would use the actual implementations and you would not be bothered but at the end of the day it's once again the trade-off so what won't you what you want actually do you want to have the quite extensible and and flexible api which allows you to add the behavior to your mocks or you want to create the i want to use the actual implementations and you will not have that much isolation on the each unit tests but yeah and and and you would actually need to create this somehow uh manually probably so you would also feel the pain when instantiating the objects but on but it would be more like error prone and you would not be doing this artificial uh setup for your mocks every single time just to call let's say one one line of uh one line of code so i'm honestly this is why i'm not feeling very good about um testing the command handlers anymore i think that doing some sort of unit test for the domain is crucial and i would stick to that but the other thing that level of the test that i would probably suggest would be more like on the api level so checking whether this actually gets persisted somehow rather than going through those scenarios but sometimes it's it's it's also useful so this is why i'm showing you how you can actually achieve it so a var exception actually i can sorry no in this case i will have no exception anymore sorry so this will return me the default of packing list for now because i don't want to make any weird uh like nasty overcomes of this of this issue and yeah at the end of the day it's just a matter of whether you want to what strategy you would like to use i can actually do this in this case so should be now in this case and i want to make sure that the repository gets called so i'm just going to do this by though doing the repository then received then how many times so i'm expecting one call and then add async and in here i'm saying that yeah this just should be of any type of packing list so i just want to check whether this orchestration on the handler actually uh works and whether this gets called i don't care about the payload i could do this but in order to do this i would need to create the packing list first and yeah it's not something that i would like to do right now so this test pass yeah it passed actually and this one of course if i will rerun it with the correct order this also works so to sum up when it comes to testing i would strongly suggest doing this for the domain for the command handlers if you're not if you have no issue with the fact that there's quite a lot of setup for your mugs this is cool but uh if you would notice during the let's say the maintenance phase of your project that even small change which actually does not change the actual behavior of the handler requires a lot of changes within the tests this is some sort of symptom that probably you're testing too low and maybe it's time to change the test strategy maybe try to go slightly higher uh maybe in this i if i will not forget uh during the editing of this video i will link in the card of the youtube the uh presentation of uh jakob dalik which is the polish uh architect uh and and he's got really cool presentation about the test driven development and uh the strategies for testing the verticals uh within the modules and how we can actually tackle this particular issue but yeah you also have some sort of example strategy of how we can arrange the tests over your cqrs handler one more thing because i've covered of course the command side for the query i would simply don't write any test because it's rather stupid i mean you will every single thing that you'll have within this command this query handler will be mocked so it's like you're mocking the result that you would get from the database and you would write the test on top of it so it's rather the test which would verify whether your mocking framework works rather than checking whether the the mapping is actually correct or the result or the query from the from the database is is correct so i would i used to do that to do that it gave me absolutely anything rather than more test code to be maintained um just don't bother yourself with that i mean it's seriously it makes it makes really no no sense to me the right side and now since you have this separation the right side is the one that changed the state of your application and this is the one that you should really pay attention to but reading is like seriously i mean unless you have like really critical thing that needs to be tested then but then i would rather go for the integration test rather than the the unit test with the isolation of your database source it's ridiculous so actually took a while uh more than i expected probably my beard grew up a little bit and my t-shirt is no longer black so yeah quite quite uh quite some time that actually i spent on recording this but yeah i honestly enjoyed that process uh that was kinda odd because the peter was not with me so yeah it's kind of weird to talk to just to the camera but this is how it is and and and hopefully you enjoyed the whole material hopefully you find found it useful and uh yeah at the very end i just wanted to discuss the applicability of this approach so as you might already feel this uh whole clean arc architecture stuff it at one hand it's very cool when it comes to the fact that this is actually the main centric and this is great for the domain separation application separation and the infra but on the other hand this might be also kind of overwhelming when it comes to the amount of the boilerplate code because now everything needs to have the dedicated class sometimes we also had the factory the policy now instead of one application service i ended up with like five command handlers the queries query handlers quite a lot of stuff so i truly believe that for some of you this especially for such a simple domain but that was one of the assumptions you might feel like this is like too much or might be too much for your project and and honestly i i fully agree i don't think like the clean architecture is like one universal universal approach which you now follow for every within every project i think that it's rather fine for the projects with rich domain uh in which this domain separation actually makes sense because if you have like very simple application like the crat you know i you can you can you can apply the clean architecture i i've done this a few times in the past but honestly this is like the obfuscating the fact that you have the crat and putting and you're putting this just into let's say more robust more sophistic sophisticated architectural style but this besides the fact that now you need to write more boilerplate it gives you nothing i mean there's no advantage of doing this because you've separated domain which actually doesn't really exist i mean you have i i wouldn't necessarily say that you know the situation in which ui represents your you know table on the database whether you know changing the properties in this table actually is some sort of domain logic i mean in most cases you can just apply it by regular mvc controller applying few data annotations attributes and this should work just fine and and you would finish up the whole work like 10 times faster rather than putting everything into aggregate and creating the custom exceptions probably doesn't make sense so what i'm trying to say is that if you feel like your application has some sort of rich domain this is the way to go if not just stick to either layered architecture or probably even flatten the version very simplified version of this in which you just you know sometimes even db context injected into controllers which in most cases sucks but in if you have very if you have don't have this this domain then why not i mean we at the end of the day you need to be pragmatic uh also remember that sometimes i mean in most cases when it comes to new project and and the product that we are products that we are doing and that we are making it's not like the domain complexity is always the same i mean in most cases the domain complexity spread all across different modules so you might have few let's say in terms of ddd you might have the core domain which is the heart of your whole system and and typically it's also related to the money so in this case applying all of this together let's say with domain driven design which is also in most cases not applicable globally into your project it makes sense to go fully into clean plus domain driven design but other more you know straightforward modules which are obviously kratz uh yeah you can just leave them leave them quite uh relaxed in terms of the architectural style maybe just try to come up with some sort of simplified solution which will not require that much boiler boiler plate code so this of course if you follow us leads to another topic which is actually going to be this second mini course handled by the peter so modular monolith the one that should actually appear at the very first time so the modular monolith mini core is done right and uh in today you you've learned the clean architecture and its benefits and how this might look like and once the modular monolith uh course will appear on here on the youtube you will see how this can be just one of the many modules uh or one of the many architectural styles being applied into your into your application and how you can make the very cool separation not only in terms of architectural layers but also when it comes to different subdomains within your application and how you can actually integrate all of that still being within one process being within one monolith application and not necessarily going um from the day one to to micro services and to the distributed system in general so this is it i wanted to thank you very much once again and if you like this this material you can subscribe you can give us a like if you have any questions or you want to call me an idiot or you want to appreciate the work that we've done you can leave a comment i will do my best to answer all of them and uh one more thing of course as since this is some sort of uh foundation of this channel of course the source code is available by the by the time that you're watching this it's it's already on github um one thing though is that because it's as you probably um as you probably noticed when it comes to length of my beard and the the the fact that i've had different t-shirts yeah it took me quite a some time to actually record the whole material so i started when there was no net six released now since we have like lts version being released i will migrate the whole code to dotnet 6 probably and yeah and you will have this available on top of net 6 and c sharp ten and yeah this should work just fine i think i think that when it comes to transition from dotnet five to six there should be no changes to the code itself it's rather the version of the net underneath which which needs to be changed so yeah i think that's it thank you once again and we're going to see definitely within this year a few more times in more shorter version of the videos probably related not only to the programming that much see ya you
Info
Channel: DevMentors EN
Views: 103,317
Rating: undefined out of 5
Keywords: #devmentors, #clean, #cleanarchitecture, #CQS, #CQRS, #Command, #Query, #DDD, #DomainDrivenDesign, #architecture, #layeredarchitecture, #ntier, #cleancode
Id: NzcZcim9tp8
Channel Id: undefined
Length: 522min 40sec (31360 seconds)
Published: Mon Nov 15 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.