Clean Architecture in .NET 7 | Intent Architect Webinar

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
okay how's it everyone welcome welcome just want to welcome everybody to uh this next webinar as you can see it's a bit of a cold day outside or at least a slightly overcast and miserable day in Amsterdam today and I just arrived basically yesterday back in Amsterdam it is it's green on this side of the world and I just want to say just uh again thanks to everybody who is joining us today we've got quite a big turnout um and I'm very very pleased to uh to be presenting to you to guys today um we're going to be doing a deep dive into the clean architecture as part of today's Workshop as part of the session we'll basically look at a clean architecture in.net and we'll be unpacking all of the different components within that and really some of the advantages of course of the clean architecture why we do the things that we do as well as some of the nuances that exist within the way that the clean architecture is implemented in.net in the with a set of patterns that intense Architects is essentially bring it to the table and we'll run you guys through that in a lot of detail and along the way I just wanted to mention that you guys are very welcome to uh to drop questions into the Q a uh the Chat is enabled if you want to do if you do want to get to some of the panelists basically I have a few of the guys on the team a few of the Architects you guys will probably know them it's John Joel and Andre in the background and they'll answer your questions so if you guys do have any questions along the way you're welcome to ask ask them there on the Q a and they will respond and they'll be there for everybody to see um I do also want to just mention that at the end of the session I do want to do a q a so if you do have questions that you'd like to raise and you'd like me to answer them we can spend the last 10 15 minutes at the end of the session going through that so yeah looking forward to it and I think without a further Ado very happy to jump in so really just to give you an idea of how we want to go about about this I'd like to just share with for those of you who are not necessarily 100 familiar with the clean architecture I want to give you a little bit of background that's what we're going to start a bit of the conceptual sides of things we can then get into some of the benefits of the clean architecture like so essentially what are some of the non-functional requirements that it's aiming to achieve and how does it manage do that then what we can do is we can jump into intent architect we can get a clean architecture on the go and that's when we'll really start getting into the detail of it and that's really the meat of what we're going to be talking about today okay so I think the first thing I want to do is just quickly share a presentation that is running at the moment now just give me a second I'll get that up um all right so the first thing that I wanted to throw up here is that this is this is the clean architecture in the Uncle Bob style of presentation so if you go Google arts on the internet clean architecture you'll absolutely find this article uh or at least an article that has a diagram that looks something like this obviously we've just uh it's brought it into um a slide deck on our side there is a link at the bottom there to the official clean architecture by Uncle Bob from back in 2012. now the one thing that I can mention here is and this is the most important thing is that the clean architecture fundamentally is really about a set of dependencies so how are things related from a dependency perspective and if you look at the diagram we've got a set of entities in the middle this is where essentially uh the idea is that the Enterprise business rules will exist in the middle of the application you've got the use cases which are the application bills the application business rules around that and that is depending on these entities then we've got the interface adapters the things like the controllers the gateways the presenters essentially these are adapters that exist around that and the dependency there is on the use cases and then finally we've got you could say our Frameworks right so these are the uh the web Frameworks uh the technologies that we're using the databases and so on and so forth and so the whole idea here is that the dependencies are moving Inward and that the inner dependencies are not aware the inner you could say the inner Concepts or the inner concerns are not aware of the outer ones and that's a very very key concept here it does also help to understand that when Uncle Bob looked at setting up this clean architecture it was really bringing together the different other types of architectures that achieve very similar things and this is his attempt at bringing together the concept into a singular diagram and this is essentially what he sent out but very similar architectures are things like the exactly architecture the onion architecture and others and um if we took a look at just a hexagonal architecture it is very much the same thing just expressed slightly differently so of course the nuances of each of these architectures is a bit different but at the same time the principles and especially the principles around the dependency is exactly the same so in exagger architecture we talk about a domain model in the middle that's also where the Enterprise business rules will live you've got the application Services which is essentially your application layer around that and then we we've got all the adapters that are there to connect us with other framework related components so things like you know certain clients in the equation so this could be databases it could be our UI it could be buses and so on so forth and these are all handled by the adapters and just to give you one other example here just to kind of really give you a feel for how these all fit together is if we took a look if we took a look at Microsoft's DDD orientated microservice architecture it is exactly the same principles they do simplify a little bit in the Microsoft way that they like to operate and so we've got the domain model in the middle and we've got the we've got the application layer depending on that and we've got the infrastructure layer depending upon that and then what they like to do is they like to say that the application letter depends on the infrastructure layer and that's technically not correct from a very from a clean architecture perspective but Microsoft does tend to encourage guys to you know write a lot of their business logic directly against Entity framework and so on so forth but that's why I've highlighted if you look on the right there there is a user repository implementation Clauses ideally through Di and if you manage to do it put the interfaces in the correct place so your repositories or your services from your infrastructure layer in the application layer those interfaces are there then you would invert the relationship but just for uh just to keep through to the original document the original uh article by Microsoft I we just decided to keep this uh this dependency that way around but just keep in mind that that wouldn't technically be correct in the clean architecture way so when we take a look at the clean architecture the dependency rule really allows us to do quite a few things and all of these architectures that we've discussed so the external architecture the onion architecture uh Microsoft's basically this is a layered architecture that they've put over here but uh this is really around that DDD orientated Microsoft microservices architecture uh one of just one thing I wanted to mention is that DDD tends to follow a lot of these principles too so while DDD is not a requirement for the clean architecture it is a uh it fits in very very nicely with the approach and DDD in a lot of Senses is quite a purest approach to building on software systems in an object-oriented language but let's just talk quickly about what uh what the clean architecture brings to the table and why we ultimately want to use it and so all of these architectures that we've discussed the clean architecture the onion architecture the Snowman architecture is another one that has very similar principles all of these uh bring forth a set of very important um uh features essentially and so the first is that we get independent we basically build the systems that are independent of their Frameworks so the architecture no longer depends on the Frameworks that are being used that's very important uh it makes them testable uh so this is basically because the business rules are independent of the Technologies because if you remember that the the domain and the application layer aren't aware of the outer rings in that original diagram we're also able to get these independent of the UI so we can change the UI quite easily and an example of that if you take a look at the Uncle Bob documents he gives the example of replacing the web UI with a console UI or having both and that shouldn't affect the actual the uh the architecture and the business rules of the system um it also allows us to build our systems independent of the database all right or any infrastructure for that matter and so the business rules are not bound at all to the database and so you can in theory swap out for example an oracle or SQL Server a database for a Cosmos that is sometimes a little bit of a stretch in my opinion uh just because oftentimes when you do design databases from a with for example in a relational database or if you design the database on in a document store like Cosmos the approach that you'll take is quite dramatically different in terms of your design so it's a bit of a stretch but it's not impossible to achieve this depending on the complexity of your system but the principle is there and in theory you would be able to make this kind of a this kind of swapper if you if you really wanted to and then finally this also allows us to build systems that are independent of any external agent so we've talked about the database the UI these are actually really just external clients or these providers and Technology providers for the system and external energy agencies could be integration points and so on and so forth and so because of the business rules don't know anything about these they're just talking to interfaces um how the how these things are implemented the systems can essentially evolve independent of all of these external agencies and services and things like that that they're connecting to so what does this ultimately lead to if we were talking about uh the non-functional requirements is as you can see that because we're building everything in such an independent way it's already mentioned there but we've got testability but maintainability is very important one of the major non-function requirements of this if you're building larger systems for clean architecture really brings the table uh the ability to have very very highly maintainable systems in the long run all right so that's a very big component and of course as part of that it allows them to remain flexible so you can see how a lot of the examples that that Uncle Bob gives as part of this is swapping things out that is really the idea but it's also allowing us to evolve those Technologies independent of the business rules and make sure that our system is tested at least when it comes to the business rules those are tested irrespective of the Frameworks they were ultimately using all right so that's really the high level of the clean architecture from a theoretical perspective of course there's a lot more reading one could do on that um these links obviously they'll be here and this webinar is being recorded and so you will be able to jump onto those links and I'm sure you guys can do a quick Google if you're interested the principles here are very very key in building software systems that have to last that have to that have a long shelf life that need to be maintainable that you know there's new business rules the the clean architecture really excels at those kind of systems it does you know if you want to have to say what is the downside of clean architecture uh the one downside that it does have is that sometimes for developers that are not familiar with it it has a little bit of a learning curve it's not a big learning curve at all but it does have a little bit of a learning curve other than that it is all pretty much upside and of course there's a cost to any architecture as well so it is a slightly more complicated architecture you can fathom easier and simpler architectures uh too but it does because of the benefits it brings to the table the testability maintainability and flexibility in the systems it really is a fantastic architecture and we've seen many many successful systems and large systems in fact built in this way including microservice architectures and following DDE and so on and so forth okay so what I'd like to jump into is I'm going to share my desktop and um we can jump into actually uh a setting up a clean architecture a real world clean architecture so just give me a second I will get this shared and uh that should just show up my throw up my desktop there and I'm going to launch intense architect uh just jump to the other monitor all right okay so if we wanted to get a clean architecture in the mix um we have a standard Keen architecture in.net application template we're not going to focus too much around the intent architect related aspects as part of this webinar it's really just a deep dive into the screen architecture but of course getting us set up and getting us there very very quickly is best done with uh what is very easy to do with intense architect at least so if we wanted to we could create something called webinar dot I'm going to create something called invoicing over here so let's say we wanted to create an invoicing application or an invoicing uh microservice per se we can go ahead and create that over here and we can call the solution name just webinar and before we jump into actually creating it we can just talk through the different patterns that make up this architecture in.net so at the top here we've really got and this is infrastructural so this is actually part of our framework set that we're using we've got the asp.net core this is for our controllers for essentially for our restful Services as well as for the startup of our application and the hosting of it we've got the JWT Bearer tokens for authorization authentication we've got Swatch buckle for the open API and then we get into our application layer where we're using a mediator pattern now the mediator pattern is not a requirement of the clean architecture but it is a very common pattern that we see when teams build out clean architectures because it really allows us to achieve amazing separation of concerns in a way that's very difficult to achieve if you are doing it without something like a mediator so when we get into it a little bit deeper I'll show you guys exactly how the mediator works and how the pipelines are set up but what it allows us to do if I could just give a one minute overview as it allows us to essentially build a pipeline so whenever you want to dispatch a command or a query which is generally the approach that the mediator takes but any kind of request into the system you would pass it through a pipeline which is set up and implemented in a cross-cutting way for that for the mediator and so this will allows us to put in all of these different cross-cutting concerns things like transactionality you know to work you know we can have security and so on so forth all existing inside of our application layer which are which ensures that those aspects of the system are insured as part of any request that comes into the system so it keeps the separations very very clear clean and it also allows us to not repeat ourselves so if we didn't have the mediator pattern we would have to build these kind of cross-cutting concerns we'd have to build them into our middleware on asp.net core and then of course that wouldn't exist if a message came in from a message bus into the system and so we would have to re-implement it over there or find a way to reuse that where the mediator allows us to do this without having to without having to essentially repeat ourselves so it's a really fantastic pattern and um and one that once one wraps the head around it is a it's an excellent way for us to ensure that every single time we make a request into our system that certain cross-cutting components are covered and that there's no mistakes uh then the other other pieces of the uh or other patterns that are employed here we've got Auto mapper uh just for mapping out the domain entities to the dtos now one thing I can just mention on this is that we never when it comes to Technologies like automapper you do not want to map your order your inbound details onto your entities okay this the way that this is set up and the way that the pattern is created inside of this architecture using these patterns is that the automaper will really only allow you to map domain entities into dtos but not vice versa and that's very intentional we have seen teams that will go and use automapper to in fact Auto map their details onto their entities but in a lot of senses that can be incredibly dangerous and it can in a sense also cause a lot of bugs it's also uh it's it's very risky if you've ever had a bit of an experience with automapper uh where you tried which dealing with collections so we really do not recommend taking Auto mapper even though you can to take Auto mapper and allow it to map inbound details onto the entities because it is extremely risky and can cause all kinds of bugs in your system collections are just one example of course you could automatically set things that you really didn't want to set if the dto has information on it that uh you know that was lying around for example maybe it wasn't on the front end maybe that field wasn't displayed on the front end but it was on the on the dto and so a hacker could exploit that just as a simple example and auto mapper would apply it straight away so you want to be more deliberate even if you're using an anemic domain approach as opposed to a rich domain approach more like DDD even if you are using an anemic domain approach which is what the example will run through today you still want to control that business logic very explicitly so that's something I could just mention on that for anybody who is considering using automapper to do their environment mappings uh we don't recommend it you can absolutely do it but it's it's very risky uh and we've seen a lot of mistakes a lot of bugs come out of a net approach where we do come across it um fluid validation of course any system you want to be able to do some basic validation of your inbound requests uh post credit support is part of the standard intent architect set of patterns just for automating the predictable repetitive crowd work pagination entities these are of course patterns that you will need for any system uh value objects and domain Services if we're doing DDD domain Eventing we'll keep that in place because we want to talk about that a little bit this is not really a requirement of DVD but it's a fantastic uh stick pattern to ensure that we don't have to write the same logic into our handlers our Command handlers or query handlers typically command handlers rather because this will really be orientated around the mutations in the system but you it can really save us from having to write the same logic in many many places it can ensure that things always happen are guaranteed to happen because we can essentially invent them out of the domain you will absolutely see a pattern like this if you're dealing with DDD but it is a great pattern nonetheless even if you aren't all right so and then the last few things that we've got chairs we've got going into our persistence this is essentially infrastructure we've got Entity framework core this is for uh persisting this is the RM everyone's probably familiar with us but this could easily be a Dapper it could be uh the you know the the app ER version of it um this could easily be a and so on and so forth so it really does the cosmos DBS so defining it as well we could have any uh persistence but this is all as part of the infrastructure and we've got a repository pattern here now one of the reasons why you'd want to bring in a repository pads and just generally speaking is that a repository pattern ensures that we are not coding against our database technology all right it means that we're coding against an interface which is the repository and that the repository implementation which would exist in our infrastructures we'll see shortly when we jump into the actual code that in that implementation will um we'll we'll have all the technology related uh you know in nuances but the app the the application layer and the business logic written in the application layer will be doing it against an interface and that makes it testable and it means that if we do ever need to evolve our technology layers in the persistence whatever that may be whether it's actually going as dramatic as swapping out an Entity framework for a mongodb um if we wanted to do something as dramatic that as that we can actually achieve that all right not something that as I mentioned you would do easily especially in an existing system just simply because relational databases are oftentimes designed quite differently to document stores for many reasons and then of course we can bring in uh mass transit if we wanted to do Pub sub and if we need multi-tenancy we could bring in front Buckle but these aren't these are just additional you could say this is an additional adapter that's an additional adapter in the system if we're thinking back to that hexagonal architecture the asp.core is essentially an adapter these are all part of the framework layer and the the technology layers of our application okay so if we're happy with this we can say create and we can just get this installed and while we're waiting for this um we can just watch it install over here I'm just going to bring that across so we're just getting some warnings here because as we've released version four of intent architect which has come out very very recently I'm sure you guys have got the the email um there are some modules that still exist that are saying that they could that they are not compatible with version four so what we want to just quickly do here is I think the application template is essentially just waiting for an upgrade but we can hop in to our updates and give that a second to load and once that's done we can just update everything and this will make sure that all of our modules so these little warnings here that we're seeing is essentially saying that those modules are are not compatible with this version of intent architect even though they are because uh version four if you guys recall is compatible with version three but when we set up the modules we always lock out the next major release because we are anticipating that there will be breaking changes but it just so happens that with version four we kept everything fully backwards compatible with version three modules so that's why that is showing up the way it is all right so what we can do here is we can just go start rolling out this application very quickly so I'm going to go ahead and design it um we can create the code base in a second but what because this is an invoicing application we can go ahead and create the concept of an invoice and it's actually just sent this over here we can have an invoice we can also just have an invoice line uh we'll just need a product Maybe uh we just need to get some stuff here so we can work with the system maybe we'll need a customer we'll also need an address of where that customer is you know the billing address and so on and so forth you can drag that in customers over here and we can essentially just fill out a domain so we just want to have something in the system for us to look at so that we can we can reason about the clean architecture at a high level so I'm just going to fill this in very quickly so we're going to have a one-to-many relationship over there and we're going to have a minute to one relationship over here so each invoice will have many lines and each line will point to the product uh we can have the invoice will belong to will have a customer that it's for and of course we can specify the address and uh you know one of the things we would typically see in the system like this is you would see maybe this address would be a billing address for example and then maybe you'd have another address over here which would be the delivery address and it could happen that's this is a you may have a delivery address we'll fall back on the delivery on the billing address rather and we'll just make those one to ones and one to zero one relationship like this okay so this is our domain if we wanted to just fill a few things in just so that it's got a bit of meat so let's just fill in the customer so name surname email address you know yeah I'm not sure what else we can put there uh product would probably just also need a name and a description and you'd probably have some kind of like a URL image URL potentially in the system I'm not sure on an image on an invoice you never know maybe the company wants to actually show the picture of it an address would maybe have a line one line two a city and a postal code and so on and so forth then the invoice will probably have a number right which can be an integer if we wanted it to be that and it created date it could be a daytime all right um last one thing here just to just for completion's sake let's put in the quantity which can be an integer and then we'll have the amount which would be a decimal if there was or we can actually make it a money type if we really wanted to all right so that's our domain um we can let's just actually just kick off the soft to factory get this generated so that's just going to go and put that in place and then we can hop over to our services and uh let's just go and you know use this accelerator here for the crowd systems to create a customer uh we can go ahead and do the same for the invoice and you can see we're really just targeting all the aggregate routes here essentially I just create all of those and that'll basically set up all of our uh all of our different endpoints so that you can see we're getting uh all of well actually now these aren't the endpoints these are the commands and the queries themselves if we wanted to get the endpoints in here just in terms of the controllers uh let's just go we can basically say expose as HTTP endpoint or Ctrl shift e I can just use that shortcut there and those will that'll just go set up the controllers for us very quickly all right perfect so there's our controllers we can apply that and this is just getting our application very very quickly set up uh we can go and open up the location over here and we can jump right in to the code base all right so give Visual Studio a moment right so the most important thing here is first and foremost you guys will notice that the structure of this application is set out and you for those of you who are very familiar with the clean architecture and intent architect you'll know that the structure is really set up by default inside of this Visual Studio designer so we've got the different uh and we can see this actually in the in the actual Visual Studio over here but we've got the different layers so to speak or the different uh Rings essentially broken out into different projects that way we can be 100 certain as developers that our domain for example does not have any dependencies so if we take a look at the dependencies in the domain we'll see that there really is only the Roswell Weaver attributes which as we all know is not a dependency of a runtime dependency at all it's just metadata for the code Management systems but this is essentially there's no project dependencies there's no nuget dependencies on any kind of framework or infrastructure that's required and so this is completely technology agnostic and if we were doing a DDD approach this layer here would have or this project over here would have pretty much all of the rules within our within our system from a domain perspective okay so all of the Enterprise rules would essentially exist inside of our domain over here if we are doing more of an anemic approach the application layer would probably have most of those rules so it really depends in DDD a lot of the rules will go in here and in an anemic approach those same rules would exist inside of the application layer alongside all of the other you could say application layer rules okay so the application layer rules are I think of this like the verb layer it's like what can you do to the system you can create invoices you can get in you can view the different invoices you can create customers you can create products and so and so forth and those are the things that we can do to the system the rules around that would exist within the domain but if we took a look at the application layer of here you would see that from a project perspective it once again depends only on the domain so this does not depend on our infrastructure uh this is really what I'll say in terms of the Microsoft approach where they were saying that this layer here does in fact uh depend on the infrastructure they did say they did right there that if you ideally you are ideally using dependency injection and if you put your interfaces in the correct space you won't need to create that dependency rather it'll be the inverse of that so we're basically doing an inversion of control here and so what we can see is that this is also as technology agnostic as we can get it because we've also got a very these are very lightweight Frameworks and these aren't essentially the way the way I distinguish between these is that these are not adapters to any kind of third uh external system external database or external API or client or agency or anything like that these are uh you could say one they're c-sharp libraries that are that have no other dependencies besides themselves okay and or at least the dependency that they have will be to other c-sharp libraries that don't have connections to other technology and so things like automapper is really just an accelerator right that's really the idea here is it's an accelerator it isn't something that is required we could always write out the mappings ourselves but this is an accelerator fluid validation is a very succinct way for us to reuse a validation system and keep a great separation of concerns so that's why fluent validation does really count as a technology dependency per se mediator is really just the system which dispatches our commands or queries or any kind of request over to the handlers and so once again the distinction here is that this is not trying to connect to a database it's not trying to connect to a third-party API it's not actually using any Technologies per se it's these are coded in vanilla C sharp without any dependency on any kind of third-party Frameworks outside of themselves okay so it's a little bit of a subtle distinction because things like Entity framework is very much a technology which is talking to databases and uh and other resources essentially I think that that's maybe the best way to describe it is it's talking to other resources and that's what we do not want to see in here so we don't want to see any very heavy duty technology and this is these are really very lightweight and very focused around making our lives easier uh inside of the application layer but definitely not requirements okay so these this is the application there that's the domain we've got the infrastructure now this is quite interesting because what you'll see here from a project perspective is that this is depending on the domain and the application and the reason that that is the case is because we've got this inversion of control the infrastructure is essentially responsible for implementing a lot of the interfaces that would exist between the domain and the application layer so the interfaces exist for example couple of the repositories these exist in the domain okay just as a set of interfaces they're completely technology agnostic so you can see that they've got uh you know we're just talking about uh products which are is inside of the domain two as you can see there we've got the general repository over here with uh you know as you can see all of this is completely technology agnostic as well and so all of these are now all of these interfaces while they exist in the domain are actually being implemented inside of our infrastructure and we'll go through that a little bit later okay but the most important thing here is that the domain and the application layer do not depend on the infrastructure it's actually the inversion of that and that way we've actually set up our application and domain to be very very testable because one of the challenges that you will find is that if you connect everything to the infrastructure you can't write tests for those systems without actually either mocking out or or running that infrastructure ideally the interfaces allow you to mark that infrastructure out which is exactly what we've gone over here because we don't have a dependency on the infrastructure we've got a dependency on the interfaces okay the other things that we can see here is just in terms of the packages is here we see very uh more heavy duty Technologies so mass transit this is for bus so once again we've got an external resource that we want to be talking to so this is definitely part of our Technologies uh technology layer with an Entity framework this is also uh you know talking to a database could be talking to a SQL server or an in-memory database or it could be talking in this case it's talking to an in-memory database as we can see over there but I could easily be talking to even Cosmos if you guys are not aware of that but empty framework can also connect to Cosmos but we could be using postgres or SQL server or MySQL or any of those as well and then finally the last thing we can see here just in terms of the uh the API layer okay this is essentially our distribution layer and this is also a technology layer because it will have dependencies let's just take a look here it'll have dependencies on our application and infrastructure all right so therefore by extension it would have a dependency on the domain but one thing that you saw earlier is that we were talking about dtos and entities in order mapper you do not want to send your your entities over the wire what I mean by that is that you never want to pull your entities out of the database and just send them through your controllers out to the to the world that is a bit of an anti-pass and there's many reasons for that the first is that of course depending on what you're pulling out of the database um and how it's been how it's been structured so I've entity Frameworks there you may have lazy loading you'll end up essentially serializing a lot of your database in one go all right so that can be that that can be very bad from a performance perspective you're also exposing you could accidentally expose a huge amount of data which you never intended to expose um and uh which would obviously be very bad as well and then you can also end up with depending on how your domain is structured you could end up with cyclic references for the for the Json okay it's for your whatever serialization technology you're dealing with and so that's another reason why it's just an absolutely terrible practice we do see that quite a lot Microsoft actually did suggest a lot of those approaches and the reason that Microsoft does that we believe is just because they try to make it as easy and un as simple as possible to use their technology set even if that means that what they start recommending off the box is a set of bad practices uh so you can't really build large Enterprise systems that are very robust and bug free or at least uh have very low bug accounts as they evolve using the principles of sending entities over the wire and things like that but that said I'll just mention that you can still do it and you can still build a system uh it doesn't mean that you've you can't achieve building software if you do decide to actually send your domain entities over the wire we would just consider it a very very bad practice and something that we wouldn't recommend for or something that we would at least recommend against all right so let's just take a look through uh the last thing here I was just about to jump into the controllers but before we go there I just wanted to point out that we do have these dependencies of the project dependencies and then above this we've essentially got asp.net core coming in as part of this um and uh the asp.net core is the uh is essentially going to bring in a lot of our uh it's probably got the standard dependency injection we've got all of the different you know the middleware fall of that as well as the systems which can essentially convert our control we'll handle all the incoming requests through the controllers and so on so forth so this is absolutely part of our technology layer we could have swapped this out if you want to think about the clean architecture in this regard you could be building this as a WCF application not that anyone does WCF anymore but we've got restful and restful API over here we could have decided to switch over to a graphql API or a grpc API or any of those things that will have all of them at the same time without actually changing the application and domain okay similarly on the in on the infrastructure side of things as we discussed earlier we could swap out the Entity framework for a mongodb or a cosmos DB or a couchdb or any of those and we would not have to change our domain an application there because they are completely independent of these technology layers okay so I think that that is hopefully very clear at this point um what I'd like to jump into is let's start going through this application from top to bottom that's the way that I like to go about it is you know if we took a look at the startup so this is a very standard startup we don't need to spend too much time here it's really configuring up the services and configuring up the pipeline okay all of the different configurations would be listed over here so this is just for security and our swashbuckle uh the different dependency injections are dispatched so if we this will be inside of our application layer okay so there you can see there's a dependency injection for our application there excuse me and this is the dependency injection for our infrastructure okay so this is Radio startup it's very very straightforward and simple of course any other components that we wanted to bring in over here Services we would probably want to it depending on what they are you'd want to do a very similar pattern of dispatching them into different configurations and just registering registering up a one-liner in this place okay in this file over here but really if we had to get into how this architecture functions we're going to have to take a look at the controllers so if we took a look at the customer's controller just as a simple example we've got uh a mediator basically the eye center this is a shortened version of the mediator interface so it's just got the sender on it which is essentially dot send okay and we're injecting the mediator in and then whenever we get a request in over here so we can see that if we had to do a post on API customers okay so this would be the customers um uh on the customer's controller essentially we would see here that it would go and take the command which is in this case our create customer command which is the payload okay comes from the body and it would just dispatch it onto the mediator and that's exactly what you'd like to see in a controller is you want to see it just do its function which is receive the HTTP response convert it into objects that we can actually work with and then we want to dispatch it over to our business logic and we're doing that with the mediator pattern if we weren't using a mediator we would maybe see something like a an application service over here so some kind of a i customers service and that would that would be injected over here and we would probably dispatch onto a create customer directly but I'll show you guys as we get into the mediator a little bit the advantages of taking it through the media mediator as opposed to a much simpler interface dispatch um and yeah so we'll talk about the the different approaches there as well and then once we get our result back we just essentially returned some kind of an HTTP response over here and as you can see there's our 200s over there we've got uh if there's some basic high level validation that we're bringing in here for that request return of 204 and so on and so forth so this is very very straightforward now how it works for the mediator just in case anybody on this call is on the webinar today is unfamiliar with with the mediator when you say send on a command and we can go to this command quickly so we can see what it looks like it just needs to implement this I request and what it returns this interface here we're going to circle back to very a little bit later but it's a very very important interface for ensuring that the units of work happens for any kind of command and then we just see this is the the fields and if we find this location in the code base you can see that right next to it we've got the Handler now the Handler over here is what the final destination is for this request okay for this command if it was a query it's for the query so whenever you say mediators so if we hop back into our controller whenever you say mediator.send command and you pass in the cancellation token you're ultimately going to end up over here unless something breaks along the way which we'll get into shortly okay so we would get into this code over here and we can inject whatever we need in through the dependency injection so here you can see we're just injecting in the repository and we're just going ahead and auto implementing this because it's very clear what the user wants to do based on the design that we put forward and that is that they want to create this customer little subtle Nuance over here is uh you can see that we're actually on the repository we're fetching out the units of work and actually calling a save uh that can interest some people the reason we have to do this in this particular uh circumstances because the database is responsible for generating the identifiers because we're using Goods by default but if we're using integers it would be the same story and so this the current set of patterns is ensure that as delegated the database to be responsible for setting out the identifiers and so we need to actually save this uh entity before we know what the ID is so that's why this is automatically implemented over there typically you would not have to do this and I'll show you why as part of this architecture if we jumped into um the dependency injection we can start seeing some of the nuances off the mediator so when it comes to the mediator pattern at least this is the Jimmy bogot style okay that's why it's mediator that's his uh his Library um what you what you can set up is you can set up a set of pipeline behaviors and this is the pipeline that I was referring to earlier and the order in which you register these is the order in which these will be executed and you can see here that we've got several behaviors that have been registered as part of this so if we just talk about them very briefly we've got an unhandled exception Behavior we've got a performance Behavior an authorization Behavior an event bus publishing Behavior a validation behavior and a unit of work Behavior okay so these are all quite each of these are quite interesting some of them are more geared around logging others are geared with some of the non-functional requirements But Here We Can See For example that if we have an exception so this is how a pipeline Behavior would work is when it handles itself it's essentially a chain of responsibility it can pass it it can pass on to the next uh pipeline behavior and if there are no other pipeline behaviors remaining it will end up in the Handler which was this file over here if you recall from earlier and um if we have an exception as you can see from this code if we have any exception we're just going to go log this area in the logs all right so you could have any sync we're using Siri log uh in the background so this is the Microsoft standard logging and then Siri log is essentially um adapting to this and that's yeah you can have any sync for that you can have a console sync or a database sync or a log file sync voice area log uh you can set it up to application insights and so on so forth so we would just see that this error was in fact logged if we get any kind of unhandled exception at this level we hop back we can see that we've got performance this is another logging Behavior so what it's doing is it's when it comes to the handle it's starting a timer it's going to it's basically passing it down the chain so on to the next pipeline or finally onto the Handler and then it's come when it gets back here once this comes back because as you can see we've got an await over there once this finally comes back we're going to stop the timer we're going to fetch out the 11 milliseconds and if it's longer than 500 milliseconds we're going to just log a warning to the uh to our to our logging system whatever the sync is we're going to log there that there is a long-running request and this is an indicator when we see these warnings for the developers that they may have performance problems within their system so this is just something that you'd see that's very standard as a general way to notify developers that they do in fact have some kind of a performance problem I mean you shouldn't have any kind of query in your system running for more than 500 milliseconds ideally all right so then next in the pipeline is part of our security so this is quite interesting because and this is very vanilla uh for an authorization Behavior as part of a pipeline I think this code came out of a fantastic sample that that there was uh on GitHub uh that we found so obviously as part of the research that our team did when analyzing the clean architecture is you went through multiple samples on the internet uh taking a look for what made the most sense and we did find some really fantastic ones we also found some absolutely rubbish ones but this came out of one of the Fantastic ones and this is essentially just responsible for handling the it checks on on the request type whether there is an authorization attribute um just to show you here the how we get that set up is if for example we wanted to authorize the create we could just apply this authorize over here and we could specify its role or its policies depending on how we've implemented our system and what this would do here is let's just get the software Factory to run is it would go and here we go and add this authorize on top of the command over there let's just go and maximize this so we can see it so it adds that over there and it's also going to go onto a controller and actually make sure that that is now authorized so that we do in fact ensure that the security is uh is applied across both both at our infrastructure level as well as on the command itself and um if we just come back here that's that's just we can see it there there's the authorized Behavior this is basically detecting that it's going through and finding out whether there's a role on it if there are any roles we go and validate those roles against the current user service this is an interface as you can see over there we could implement this with any kind of so if it was a you know we can use the principal claim system or any kind of system to do to implement this current user service and if it's a policy-based approach then we just delegate it over to the authorize against this policy all right so either approaches are supported as part of this you can either roles or you could do policies so that's what that behavior is essentially ensuring happens and what's great about this is that this means that the security regardless of whether this comes in through an HTTP response or if it came in through a grpc uh request uh sorry uh HTTP request or a grpc request or came in through a message from the from the bus if this request uh if there is a request that's coming through the mediator that does have an authorized attribute on it we can absolutely guarantee that we're going to check it properly so we don't have to write all of that security logic into every single one of our infrastructural components all right then after this we've got uh some there's kind of two interesting ones here there's the event bus publishing behavior in the units of work behavior before I look at those I want to just quickly look at the validation Behavior so the validation is really just coming in here you can see what we're doing is it's essentially for this request it's injecting in the validators so this is just very very neat way of doing it uh we can just check if there are any if there are we can go and essentially run them okay they are asynchronous okay it's because sometimes some validators you may need to hit the database this is an example of the validator over here so this validator uh we're just still looking at the create customer command um this is just really just checking that the name surname and email address or not null okay that's because that's that's how we set out our design so if we look at our design over here the these are all not null okay and if we were to enforce certain constraints in the database these can actually be enforced here automatically as well as part of that um and so what's happening let me just hop back into the validation Behavior so what it's doing is it's getting out any validators like this one for example and it's running it and if there are any failures it will throw a validation exception and uh this would this would out this should ultimately be handled by the infrastructure so for example inside of uh the aspina core this will get con this should get converted to a 400. uh I did a presentation on the clean architecture very recently at one of the development houses that we work with and they raised that we actually have we this this is not being turned into a 400 and that's something we are aware of and I think that we have a pattern that either has been released or will be released which is essentially does handle this exception as part of the middleware on air on the asp.net core and con and convert that into a 400 in a nice in a very clean format so if there's not out already I'll just have to check with the team but if that's not already it will be very very soon and then what we do is we pass it on to the next Handler and ultimately as I mentioned earlier it would ultimately end up here which is where we'll handle the business logic and it gets passed back up the the most important thing here is that as you can see the separation is very very clean we do not have to worry about things like writing our validation code in here we don't have to worry about putting in logging we don't have to worry about checking um for security and so on so forth all of that stuff is automatically we know that it's going to happen so the separation of concerns is very very clean and the way that it's structures is very neat and so that's one of the that makes this very testable firstly so we're able to test just this logic without getting caught up in you know validation errors and things like that and we can test the validators separately okay so we can throw the validators through a very strong set of unit tests to make sure that all of those edge cases are covered independent of the actual business logic that we want to write as part of that now validations do would count as business logic and so would mappings to some degree so you would want to test these uh you would want to test these across the system as you as you pull out your unit tests um but the one the two that I missed here was the event bus publishing and the units of work let's just take a look at the units of work quickly so the units of work is uh what it's doing here is is at a high level it's just creating a transaction scope now this is very important because if you're familiar with let's just take Entity framework for example whenever you call Save changes in Entity framework if you just if you call Save changes as part of a call to your system so there's a request that's coming in and you call say if you make some changes to an instant you say save changes and then you make some other changes to another entity and you call Save changes each of those calls will result in a transaction inside of your database typically speaking if you don't do anything else and so that can create a transactional concern because of course if the first transaction completes successfully and the second one bombs you've actually gone into an invalided state in your database and that's something that you absolutely want to avoid and so what we prefer to do here is we prefer to actually move that out into so Entity framework does implement a unit of work pattern by default okay and what that means is that as you're making changes to your entities and you're saying well this entity maybe needs to update all this entity needs to be added what it's doing is it's actually holding on to all of those changes tracking them to some degree okay it's the framework is a fantastic uh entity tracker tracking system which can really simplify a lot of your business logic code but you can also switch it off um and uh what that does is it delays the execution of those inserts and updates to when you call save all right and what this why this is very very important is because when it comes to databases if you're not from if you're especially relational databases there are locking systems in play that uh can have a massive and dramatic effect on how your system's performance is managed okay so uh it when we take a look at the transaction scope and I'll talk about that briefly you'll see that there's an isolation level of read committed now this if you're not familiar with isolation levels you can take a look at today if you are building your system in a relational database you absolutely want a familiar familiarize yourself at least with the general concept of isolation levels it's not something that's a big concern if you know that I mean I'll just say that read committed is pretty much the best compromise you're going to get from an isolation level but what you don't want when you're building a system is you don't want to escalate locks and hold on to them for the duration of the transaction unnecessarily so to give you an example if you have a much more stringent isolation level like serializable serializable is what is the most uh it's let's just see what the option is here it's called serializable that one there um what this does is it basically says if you read any dates out of the database when you read that when you read that data it will create a lock a readlock on that potentially on that record on that index or on that entire table depending on how uh the table is structured that read lock will be held for the duration of the transaction and so no one else is allowed to write there maybe other readlocks are able to come in but no other right locks are able to access that record and so you have a bottleneck in your system all right ride locks are also help for the duration of the transaction and so if you try to set your isolation level to serializable you're going to very quickly end up with deadlocks okay because you're going to have two transactions both of them start holding reads they both want to write to each other and you end up with a with a deadlock very very quickly what read converter does is it just brings it back a little bit a little bit and says well any read locks that are created if you try to read data it'll create a readlock and release it as the moment the data is returned but any write blocks that are created as part of the transaction will be held for the duration of the transaction and so that's where the units of work and this approach is very important because as you can see we pass on to the uh to the next Handler inside of the pipeline and finally over to the Handler itself and it only once everything comes back and is done that's when we call Save changes all right so that means that we're waiting to escalate those right blocks to the very end of the transaction and that's what we want to do by default what you don't want to do is you don't want to have to at least unnecessarily you don't want to call Save changes somewhere in the system then do some other reads around the system and then call Save changes again at the end because you're going to have escalated right locks for a unnecessary duration uh running on that system running as part of that transaction so you're going to end up slowing your system down quite dramatically and potentially causing Deadlocks right so that's something just to keep in mind the other thing that you'll notice here is that we do throw a transaction scope there's several ways to do this this is uh there's a little bit of an explanation here about this as well as the link to all the different approaches to creating transactions this is a very unobtrusive way of doing it and so what you can see as we just essentially set up a transaction and what this means is that should it happen that the developer does need to for whatever reason and there are reasons why you could have to call Save changes uh not as part of the standard unit of work as we saw this is one example but there are others where you for example want the database to um you do want to make some you do actually want to make some actual saves to the database or uh commits to the database um while you may be making incremental numbers and things like that and so you you may have cases where you need to call that uh and in that case it is still transactionally solid so the transaction scope it shows that any saves that are done as part of this will any save changes to the database will in fact be Atomic will be consistent will be durable and so on and so forth okay as part of that asset Rod section if you guys aren't familiar with asset transactions that's essentially what uh you know most relational databases will give you and document stores like as well as cosmos in certain circumstances can also give you asset transactionality all right so that's obviously very important then the second thing that I wanted to talk about here is the event bus publishing so this is also very important because here we can see that we're also doing essentially it's not it wouldn't be considered a unit of work but we're also whenever the events are being published we don't actually publish them onto the bus directly okay we store them in a queue essentially and once the transaction or once the business logic is all finished we go and we flush that okay so this is where this is essentially uh we can actually take a look at the implementation of this we go through the batch of messages that need to be published and we essentially just publish each one of them okay so this is actually inside so this is very straightforward this is a implementation for the mass transit of the event bus will come we'll Circle back to that later but why this is also important is because let's say You're Building A You're Building up some business logic in here and you want to create a customer you want to maybe do some other things you want to publish some you know create a customer created event onto the bus and if you wanted to do that you just want to make sure that you're not publishing onto the bus until all other all other business logic is essentially run you don't want to be publishing for example uh you know as soon as you say publish it goes up and it is actually there and then you get an exception in your database uh from you know your database blows up and then it doesn't and then those messages are essentially sent out to all of your other systems right because that's going to lead to inconsistencies uh and and you know depending on the system You're Building those could be absolutely unacceptable so having this unit of work in or equivalent of units of work we're really just having a delayed execution it's rather referred to it as that we're having this delayed execution of The Flash for our events to ensure that this happens also at the very last moment and because we've got we can we can create a unit of uh sorry not a unit of work we can have an outbox pattern as part of this so we can actually for example switch this over to an outbox pattern an in-memory artbox pattern or an Entity framework artbox pattern if we actually enable this it will make sure that the that these these events when they are being published are going to be persisted as part of the transaction to the database so just to talk a little bit about that um if you are not familiar with some of the transactional concerns and this is something that is very important when you're Building Systems especially systems that you can't have any kind of inconsistencies occurred or at least the the case of very of inconsistencies in your system can be a very very bad thing okay so Medical Systems banking systems it would be absolutely terrifying if you had transactional concerns on that front in the past how we dealt with a lot of this is we used to use DTC which is the distributed transaction coordination systems and uh you know things like soap used to have a DTC standards that you could use and so it allowed you to do things like I could have a call to my system I could do a service to service invocation to another system I could maybe even publish events and I could link all of that onto a button I could link all of that as part of a single transaction but what ends up happening is that only really worked uh when everything was being hosted on a single machine and even then it was a big a big bottleneck but if you had to actually distribute out your different applications and your different between the different service calls onto different machines and you weren't doing this you were doing this in the cloud for example um you if you had a DTC and the cloud typically does not support DDC but if you manage to if you manage to do it on a server that you were managing and you had it across a network so different components were across the network it can slow down that system I think that some of the stats were in the region of 270 times slower okay so distributed transaction coordination is just not a possibility uh these days when you're building out systems and in fact none of the cloud providers provide any kind of DTC for that matter and that's very intentional and so you have to fall back on other approaches and so the first the first approach that we can talk about here is you can just not worry about it so much okay so if we were to flash all our events onto the bus and we were in the cloud and we were using Azure service bus as an example the chances that is your service bus is not available in that moment is very very slim okay and so we can just rely on the high availability of infrastructure to deal with this which is actually what most we've noticed most teams do but that could also be unacceptable because if for example there was a an issue with there was a configuration issue with the bus uh that could be a developer mistake or for whatever reason we have actually heard of cases where certain availability was not there for a period of time you could end up with a lot of messages that don't make it out of your system and that could be an absolutely unacceptable state for your for your application because of course if those messages are not published the database has been updated and but the other systems haven't been notified and so you could have for example orders in the system but no labels created and there'll be no delivery and no invoicing and things like that but the orders were in fact created and maybe that's acceptable or maybe that's not but in some systems there would absolutely not be acceptable and this is where when DTC is not an option you can fall back on things like for example an outbox pattern so uh what the outbox pattern allows us to do is if you've got the two resources uh outside of your system which is number one the database and you've got the service bus the uh when we when we have when we want to publish these messages what we can do is if we wanted to send them to both the service bus and the database uh whoever goes first if the second one in the order were to fail the first one had did succeed we can't really fix that and you can obviously uh you know sort these things out with uh with rollback events and things like that but typically that requires a lot of extra development but ultimately you've got a case where if you don't have any kind of contingency system you could have uh you could have a lot of inconsistency and so what are you what are outbox pattern allows us to do is allows us to bring for example this publish the publishing events it allows us to actually bring that into the same resource so we actually store the events in the database as part of the transaction for the changes we made and then we pull them out and we after after the fact that we pull them out off the fact and we send them over the bus all right and so that is if you're not familiar with an artbox pattern it's absolutely worth keeping in mind and we've got a very easy way to get that in place we can just basically take the setting switch it over to the Entity framework I think we may have to actually we can just see if this will set it up for us we may have to just specify whether this is uh yeah it looks like there was some warning there but we may have to just specify whether this is or what kind of database this is actually using so this will go and set it up for the Entity framework and actually wire up the art box pattern inside of um I think we might have to change some other things here I think the warning would probably ask us to change out of a in-memory uh messaging system or uh do you specify an actual database type for our Entity framework so I'm just going to leave that off for now just so we don't cause any problems for ourselves but that's just to give you an idea if we wanted the outbox pattern if you're using a real database and you're using a real bus like rabbitmq or Azure service bus that outbox pattern is already there and ready to go so that's obviously very very important that's why I wanted to spend a little bit of time talking about this Okay so we've gone through if you if we just go back here we've gone through these behaviors and as you can see what these are ensuring is that all of these will happen Okay for the request now one thing I can just mention is that there are the units of work would only happen where this request type has I command on it so queries will not automatically call Save changes and commands will automatically call Save changes and so we don't actually need to typically so maybe a better example over here is we don't need to call Save changes so we don't need to tell the system that we need to save changes when we change the state of an entity within the system once we exit every developer can know that once we exit all of the business logic we have pretty much a guarantee that those changes will be saved as long as it came in through a command of course if we wanted to make State changes through a query you'd be fundamental violating the cqs principles and so that probably you know to call Save at that point would be an absolute anti-pattern and you'd basically be doing something quite dramatically wrong so commands are responsible for mutating the system and queries are responsible for retrieving information from the system and not and they will not mutate the system so another thing to look out for if you if you're looking for things through Google is cqs and cqrs cqrs is usually where you take the cqs principles and apply them in quite a dramatic often well it doesn't necessarily need to be dramatic but in a more substantial fashion throughout your system so cqs is really just the principles that cqs is built upon Okay so we've covered the dependency injection we've taken a look at you know this is where the business logic is as we discussed earlier when we take a look at the Domain we've got our repositories inside of the domain layer and the way that this is set out over here is that the repositories themselves the implementation will be inside of the infrastructure um so from an infrastructure perspective we're going to implement the repository and this is a Entity framework so there's the connection to Entity framework is on this DB context there's Microsoft Entity framework core um this DB context over here is essentially what we're wrapping up wrapping around with the repository pattern one could easily or swap one could essentially not necessarily easily but you could essentially Swap this out uh you know instead of using Etsy framework this implementation could be around a or a cosmos okay whether you'd be able to still pass in certain expressions and certain things oftentimes that comes down to whether the technology supports it okay so certain so certain things you might have to do some cable workarounds it depends how you want to approach that problem but this is obviously very important because here we've got the repositories here's the actual implementation of the customer Repository a lot of teams we've seen that maybe they have this generic repository approach um the generic repository approach has quite a couple of problems and that's why we actually have we you have obviously a base class but then you have a specialization of that for the specific aggregate that you're dealing with and so if we wanted to have any kind of specialized uh you know queries and things like that that we may want to do as part of the repository we could implement the technology related aspects inside of here so that's just to cover a little bit of how the data access works it's all inside the domain and the reason this is inside of the domain is because in a DVD world as well as in non-dd Worlds your domain should be able to keep itself in in a valid State and to do that oftentimes if one aggregate changes it may need to cause changes on other aggregates and so having access having an ability to access the data from the domain to ensure that those rules are in fact implemented is very very important and that's why we've got this over here so the separation is very very clear we've got a 100 technology agnostic domain layer which is able to then speak to our infrastructure through the dependency injection okay which is what we've discussing earlier um if we took a look at let me just actually hop into well let's just take a quick look at uh what I want to look at now is the it's a DB context over here so the DB context for the EF the one this is all very very straightforward and vanilla but one thing I wanted to point out here is this and this is really when we're talking about keeping the domain in an invalid State this is very much an important this is a very useful pattern to apply this is essentially the domain events pattern which is um which this is the Jimmy Bogart style uh I'll get into that in a second but the domain events pattern is a fantastic way for us to ensure that whenever we make certain changes in our domain that's an event is then published okay and that that event will be handled by some kind of a you know event handler or a manager inside of the application layer all right and so we can then ensure that if we wanted to for example uh instead of let's say that there was some additional stuff that needed to happen inside whenever you create a customer there's some additional things that need to happen we need to do some validation or not some validation but we need to change some other aggregate in the system like um uh I'm just trying to think of an example and nothing really comes to mind to be honest but if we had to make some other change to another Aggregates like let's say we wanted to activate reports and we wanted uh and we wanted some other entity in the system to be notified that it has an additional reports and they've got activated so that's an example so we had to increment a counter or something like that what we could have is we could have a domain event which publishes a report activated domain event which could be handled by a Handler in the application layer and we wouldn't necessarily need to write that logic inside of if this was the activation activate report logic we wouldn't have to write that here okay and that's very very important because uh what that means is that we if you have let's say the same logic that needs to happen in different use cases which is absolutely something that will happen in a lot of software projects whenever that same logic needs to occur over and over in different handlers you really are faced with two options the one is that you actually create a service for that and you bring that same logic into some kind of an application or domain service which again absolutely do but the disadvantage of that is that you have to remember to call that as part of your Handler so if that if that logic has to happen in three different places then you have to remember to call that logic in those three different places but what with the domain events and I'm going to show you guys an example of that shortly what the domain events allows us to do is to publish those events directly out of our domain um and then those can be handled in other locations as well so let's go and quickly created the main event and I'll we'll talk take a walk through how these are getting dispatched as well so if we created something here let's just call this the customer created domain event okay and on this we can add a property called customer which will be the customer itself okay and I can just position that over here so that we can see that this is really coming out of that and we can just run the software Factory execution and what it's going to do is going to create us our event which is very straightforward here you can see we're using a Constructor for this uh one thing that I can mention is that we we tend to if you want to err on the side of caution you should use Constructors for creating objects including entities there's a little bit of a DDD Principle as well so in DDD you will absolutely use Constructors to instantiate uh classes or additional entities and your Aggregates but what this does do is it does prevent protect against bugs because if you're using the anemic model then I can show you a good example of that little digression here but if you are using the anemic model like this if for whatever reason there was another attribute that was added to the customer like if they're an act if they're active so is active which can be Boolean if we rerun the software Factory at this point I just want to point this out if we had to apply that and we came back here you'll see that this this code doesn't break but is active is actually there okay and so if we had if we were constructing this customer in a few different locations in the system which is something that can actually happen um we could easily forget to add this here and I'll show you if we go and we actually create a switch this over to a Constructor how that protects against that okay so um we've got this domain event and I wanted to just point out here so the domain events will exist inside of our events over here in the domain this isn't over here and if we were to just see where it's being handled we've got an event handler over here called customer creative domain event handler and this is essentially got the uh going to take in our domain event this is the notifications coming in and we can do some logic in here so if we wanted to we could inject in the product Repository and we could go and do some panel beating on the product if we wanted to it doesn't really make sense in our domain but just in case we wanted to get an idea we could go and actually do some implementation in here and and do that okay um but what I can just show you as well as part of this is that this is how the domain events are dispatched so I'll show you how they're added and then I'll show you how they're dispatched so we'll get it okay let's rather go the other way around if we wanted to actually dispatch this event problem let's say the customer so if we went into the customer over here we can create a Constructor okay and we could publish the so we could say uh domain events now this is how it's published and I'll talk about this a little in a bit more detail we can add a new domain event called new customer created domain events over there and now we have pretty much a full guarantee that this will if this customer is created this will in fact um be this will in fact fire now the one thing that I can say is that this is you don't you don't necessarily want to do this like this because EF will actually use this and you'll end up firing this domain event all over the place like this so just keep that in mind we can't do it like this what we'll probably have to do is we'll have to actually go and switch over to creating a Constructor and we can say here that we want this Constructor to set let's just say the following Fields like that okay let's just run that so that we can fix this up and we can come back into our code yep there we go uh we don't need Yep this is so this is for EF okay so there you can see we need we need an empty Constructor it's protected for Entity framework but here is our actual Constructor and we can once again go ahead and do this properly and say domain event start add you and we can set it up like that okay so and that's that's obviously very important is of course if you end up calling this as part of anything that your infrastructure is calling for example The Entity framework you can create some very interesting cases in your system but this would ensure that if we construct our if we create our customer that the name sort of an email address uh is set but it also will absolutely dispatch this so if we're creating the customer from multiple locations here's just one of them we'll go fix this up shortly if we're creating the customer from multiple locations uh we have a guarantee that their domain domain event will be fired and that we will end up executing this logic and the way that we can guarantee that is when the save changes gets called and this is so we've talked about how you add it when you want to when we for these to be dispatched and for us to guarantee that in fact those domain events will end up getting handled it's done in this approach here now this is actually um if you guys take a look on the internet you can just on the Lost techies uh blog by Jimmy Bogart he's got an entire article that's dedicated to domain Eventing and the different approaches and you've got a static version and you've got some methods approach to doing it and this is of all the different approaches that you could take this has to be one of the nicest most testable approaches that's out there it's also the one that he recommends and what it's essentially doing is it's linking and this could look in with any infrastructure it doesn't have to just Link in with Entity framework but we know that any command that goes through the system will in fact uh call uh call dispatch events and so the domain events will through the change tracker check if the entries has an eye domain event on it if it does it'll fetch them out get the first one that is not published if there are none it'll break because we're in a while true and if it does have one it'll just set it to published and then publish it okay and so that's obviously what that means it's just going to circle go in a circle and essentially handle all of these so each time it publishes and this domain Services is we can just take a look at the implementation over here you can see all it does is it really just dispatches stuff onto the mediator so it goes and uh and this is this is all very standard as part of the Jimmy Bogart Style with um with the mediator pattern so there you can see we actually published this as part of that and this is by the way not a request this is a notification okay so you won't end up multiple firing things like the save changes and stuff like that because this is not a request okay it's just a notification all right so that's obviously a very subtle Nuance uh maybe easy something easy to trip over if you are trying to uh to use a unit of work pattern and and the part in the mediator pipeline um if we wanted to just fix this up quickly we would really essentially go and map this to the operation which would be the Constructor over there and this should just go and fix this up for us yeah so there you can see it just go switches over to creating our entity like that and there we go so now it's just going to use the Constructor that we set out pass in the request information and add that over there and now we have a guarantee that this domain event up here will be handled over here as part of that as part of our create okay um so yeah so that's very that's just a little bit of a high level on the domain Eventing pattern that exists in this architecture and you can see that obviously we can switch over to Constructors but the one thing the one thing about the Constructor here that you can see is if I had to go change my Constructor at this point this is actually a great example of where that bug comes in if I want to change this Constructor and I wanted to bring in the is active take a look at what happens okay so we're going to let's just double check this yeah okay so you can see what it's doing over there it's like okay you've got this Constructor but I don't really know what you want to do with that and so we're actually going to immediately get a breaking change in our system and so this is where not being anemic okay so to put in contrast an anemic domain model just by the way is really where you're allowed to hit these setters okay and so you can do things like let's just go to our products like this where you can't just set them like that and you can construct things and so this is obviously if if anybody is interested in DDD this is thought this is starting to head into that territory obviously you can follow just some of these principles without going full-blown DDD can save you a lot of bugs to give you an idea when when we uh DDD is a little bit elusive just to talk about it just for a second it's a little bit elusive at times as in um I was on two projects that we thought we were doing DDD on and it's only when I went on a course with Von vannon uh on implementing DDD that I finally realized that we weren't actually doing proper DTD and uh when we realized what we were supposed to be doing we ended up rewriting uh our one of our systems in a DDD approach which was a rates engine so quite a complicated system and uh it really simplified that system dramatically and we were able to fix a lot of the bugs that were there as part of that refactor and then all of the future systems what we started noticing was that whereas previously when we're doing things in an anemic model we had about 50 50 bugs on the front end as well as the back end but when we got into when we were doing DDD on the back end what we saw was there was dramatic drop in the bugs on the back end and so the ratio actually fell to more like an 80 20 so we had the vast majority of the bugs were in mistakes that we were making on the front end and very very few bugs were actually existing on the back end because the the way that DDD structures the code base is in a way that it's very hard for bugs to occur and it also makes sure that everything is very very deliberate and um yeah and one of the major rules there is that the domain can never go into an invalid State and so it's it protects the system very very much as well so you never have this kind of invalid State problem that can occur a lot easier in an anemic model okay so that's that's obviously uh just a little bit around uh this weekend if we wanted to fill this in we could just maybe just set that to true and uh I can just tell this to ignore itself for now or we could go and actually um we could go handle this and actually pass in whether it's required or not I mean you wouldn't want to do this uh let's be let's be real about it you wouldn't want to do it like this you'd probably say that it is active if we're going to do it let me just fix it up go back to setting this to fully and we would probably end up in doing something like this you'd probably just say is active is equal to true that would be the default it'd probably do something like that oh I see that's this is we did forgot to ignore this oh all right so the domain event would go in here at you so many events should have paid attention to a software Factory there and I can just set this over to intent managed mode and I'll just put into merge mode for now okay all right let's just put into ignore there we go all right so that's just so let's just say it doesn't delete that code again for us all right okay so other things I wanted to show you guys here is um if we opt into our Eventing so let's just talk about this a little bit when it comes to multiple uh uh like let's say you're a microservice architecture or you're actually you're just dealing with multiple systems that are integrating together you really have two typical ways that one integrates systems together and the first is uh service to service invocation so that's where I make a service call so let's say that there's a restful API that exists uh that restful API I can hit it whenever I need to and from the other system through an HTTP client or anything you know something like that and I can retrieve information from that system or I could even make primate mutations on that system but the the general uh the general problem with service to service invocation is when you're doing queries it's fine but when you're trying to do tape mutations you could very very easily end up with transactional concerns so a simple example is let's say I wanted to I wanted to create my invoice all right but I wanted to go fetch the price of the product from the uh from the pricing system okay uh that is that's quite safe for us to do because we're fetching information but if for example when the invoice is being created uh as part of let's just say this function over here if I had to inject in a service proxy to do a service to service invocation with the let's say the delivery system and I wanted to create a Weeble and I said here you know uh create Weibel as part of this now what will happen is this transaction will start it'll come in here it'll call that other system that call to the other system is a transaction which will complete and then it will return back let's say it's successful and then we try to save changes then for whatever reason we've have a a constraint in our database that has been violated or something else that's gone wrong somewhere and it will explode and so the transaction won't actually be saved in the system and so we've got inconsistency again because that external system essentially has the the weibo has been created but the actual invoice on this side has not been created or the order or whatever whatever system the transaction that was trying to save on this site has not actually been saved okay and so when it comes to queries we know we can do queries quite safely because there's no mutation in the other system but if we want to mutate this is where a bus is a much a much more preferred approach as we discussed we can even put in an artbox pattern with a bus I think the technology is like mass transit supported artbox pattern and so we can have guaranteed delivery for the systems of course if you are doing things like artbox patterns you are going to have to have item potency on the receiving side which is quite important to keep in mind but when we want to do mutations the reason that you do it through the bus is because we can ensure that the message is delivered okay or at least it's published we've publish the message and that message can get can get consumed asynchronously through the other system and if there are any errors over there uh that can be put in a dead letter queue or the developers or could basically block the queue up if you want and the developers can get down to fixing that typically speaking you'll probably put it on a dead letter q and then reprocess it once you could if there was a bug that bug could get fixed in that other system and then the systems would go back to because go back to being consistent so because it's asynchronous the term here is a eventually consistent system all right so we we're saving stuff locally we're publishing events those other those events are getting processed by other systems asynchronously and so the states and the changes of the system are occurring uh eventually all systems will be consistent with each other okay as opposed to trying to put everything together through a DTC um all right so I'm just going to quickly show you guys the stuff I do know that we're a little bit short on time here but if we wanted to for example have our product created let's call it product created event we can actually map this directly from our product itself so oh actually no listen to it on the customer because that's the one we've been playing with customer created event I can go here and I can say map from this domain select my customer I can say these well actually I want all of these fields that I want to include and I can say that this will be published as part of this and what this is going to do now as you can see in our Handler and this is the last thing I wanted to just take you guys through so of course there's just fixing this up for us I don't think I push save on that file that's probably why it's doing that and we've got our event bus which is over here okay we do need to set this to let me just check it should be set to to a uh let me just set this to fully over here because we do want to inject this we're doing it a little after the fact oh sorry wrong side let's check on the to try to merge first that doesn't seem to be happy with that let's just do an ignore I'm sorry a fully there we go sorry um belong there guys all right so we're getting this across here just want to check the merge yeah so if you put in merge mode that's perfect so if you guys aren't familiar with this we can put in merge it's going to add that over there and it's going to add that over there and um we've got now this event is going to get published as part of this the reason that this is automatically figuring all of this out is because we're looking at the name of things and we're saying based on the information you've given us uh just from a design perspective it's pretty logical what you're trying to do here if a customer gets created we're going to want to publish other customer and we're going to want to map that but what is important here and the one thing last thing I wanted to point out is that the I event bus is injected here and this is a uh just an interface that you could have any bus talk to so this publishes events you could have this is mass transit is wrapping this right now you could have Dapper wrap this that's the distributed application runtime you could have um just you know actually more uh you know a very a hard implementation offers your service bus or eventbridge or you know SNS or sqs and all of those different things you could actually implement it in any way you want but ultimately your business logic coming back to the clean architecture is independent of that which makes this very very easy for us to test and it would not need to change if we wanted to change our bus technology so guys there's a lot of stuff that I could take you through Beyond this there are lots of little other nuances that can be you know pulled out and explored but I'd like to just stop there and I'm gonna pull up the participants uh window over here so I can see you guys can just put up your hand and I will uh enable and I will basically enable that you can ask your question I'd like to take any questions that anybody has at this point all right cool guys well I assume then that that probably covers everything I hope that that was informative um yeah I would have loved to grab a couple of questions from you guys but uh thanks thanks very much for joining and uh we'll obviously be holding webinars as frequently as we can uh we'll also maybe send out a poll to see whether there's a a request on any particular topic that you guys would like us to cover so just want to thank everybody again and uh wishing you all the best for the rest of the week um yep and catch you for the next one all the best
Info
Channel: Intent Architect
Views: 14,293
Rating: undefined out of 5
Keywords: intent architect, clean architecture, code generation, dotnet, dotnet core, dotnet 7, mediatr, mediator pattern, automapper, mass transit, microservice architecture, software architecture, software best practices, software architecture best practices, restful api, cqrs, command query segregation, cqs, unit of work, outbox pattern, clean architecture example, clean architecture .net
Id: AFcOyF_TWAg
Channel Id: undefined
Length: 84min 0sec (5040 seconds)
Published: Wed May 10 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.