Contents: 01:22 Why Clean Architecture? 02:56 Layered Architectures 08:57 Architecture Tests for Enforcement 09:58 Demo: eShopOnWeb 16:56 How to Organize Code for Clean Architecture 21:11 Demo: Ardalis' Clean Architecture Template sample application 24:20 Demo: Using Ardalis' Clean Architecture Template 26:25 Learn More - which includes all the links to the repos and sites
11 дней назад
Thanks!!
Месяц назад+102
Does the clean architecture change in every new version of dotnet? 😂
And once again this talk is the most popular (non full day stream) talk in the dotnetconf playlist. Say what you will about Clean Architecture, it remains a very popular if sometimes controversial topic...
Every. Single. Year. I had some respect for Steve Smith 15 years ago, but after 10 years listening to the same push to "Clean Architecture" it just makes me roll my eyes.
The templated Core project uses a MediatR dependency and injects a MediatR-specific "IMediator _mediator", wouldn't that count as a forbidden infrastructure reference? I understand the events have to be passed somewhere, but would that require a more general infra-agnostic interface?
This is what "Architects" call "We Adopt that to our Architecture" - Sometimes you have to decide for concrete external dependencies, when they serve well, it was a good "adoption" :)
I mean, you don't *have* to... Jason and I just met for the first time last month at Techorama Netherlands. He was doing a talk on CA there (and I was not, I had other talks). It was a great presentation and his template is great, too (though I don't care for its direct dependency on EF).
@ is like a classic movie in which you have to revisit every other year, I really like Nice to know you have meet Jason can we have a collab? Thanks for you amazing work 🙏🏾
I would prefer having things in ApplicationCore (and maybe other projects) be organized by functionality. Instead of having folders Entities, Exceptions,Interfaces, Services... I'd rather have one folder for one functionality (vertical-slicing approach). This way one quickly sees which functionalities an application is composed of and it's easier to manage when application grows (otherwise lists just get larger and larger, and no one knows which files belong to which functionality).
Agreed 100%. Look for updates to eShopOnWeb along these lines in the future. It has some historical baggage but now that it's maintained by NimblePros I have a freer hand in updating it.
I saw your Specification library, it has Specification, So I wondering that TResult is the kind of DTO? but the DTO is staying at UseCase layer if I write a kind of generic specification so I have to define the TResult be some base DTO Class? that make Core layer depends on the layer which DTO stayed. How do you think about that usecase Ardalis?
For additional information, I remembered in previous video, in the slide explain what should be put in Core project, the slide showed "DTO". So DTO can be insided "Core"? Or what usecases that should put it there. Also in the template, I think you should prepare for "Grouping", right now our project based on your template and it missing the grouping in Spec so we have to write an "adapter" to adapt the situation. Thank you if you have time to read this!
Specifications support projections, which is what TResult is used for. And yes, that would usually be a DTO. I don't typically like to have DTOs in Core but sometimes it's convenient and pragmatism wins over design purity. More typically I might define projection-based specifications in my UseCases layer, which does define DTOs, and that works as well (although then the specifications aren't all in one place, which is a tradeoff as well).
I think the example project misses somewhat the point of explaining clean architecture, by explaining how to possible do clean architecture in combination with domain driven design.
All these "Clean Architecture" things look like overengineering for me. But overall the idea from ports and adapter architecture of separating business logic from everything and making it the core of the system is very useful.
I am actually on Team Jimmy Boggard. Just write everything as simple as possible, with code duplication etc, and then refactor away code smells. You will end up writing your own MediatR (so just start with it), and every handler will be in layers - pull data, modify, save (or more those 3). Unit test the modify, integration test the handler - done. When you refactor, you will extract shared code into a service - don't start with a service. If you are using EF Core, it already is a repository. If you refactor enough, you will actually get to "DDD but no sweat" - and it's great end goal, not starting point.
That all works, yes, if you're good at refactoring and know what to refactor *to*. If you don't, having some up front rules or policies to follow can be a big help toward ensuring you don't end up in a hole you can't dig out of. Also, the repository pattern is an abstraction that belongs to your domain model, not a concrete implementation that is part of the framework or some third party. Thus, EF Core isn't "a repository" but is a specific persistence library. There's an important difference.
Try using this with something else than Entity Framework. Both specification and domain events are hard-wired to EF. This is not good separation at all.
Both are implementation details. Specifiication has a separate package that provides EF6 or EF Core support. One could add others, or use the library without either ORM if you wanted (though it might be limited to in-memory evaluation at that point so obviously much less useful). You can implement domain events wherever and however makes sense for you. Doing it post-persistence is a design choice, and having made that choice, tying it directly to SaveChanges(Async) in the DbContext is simply convenient. But changing that would only require a single change.
@@Ardalis Thank you for your reply. I agree with the domain events, personally I would just use something like mediator and call it from a service. For specifications, it's more difficult. I use clean architecture and I don't use DDD, but I do draw inspiration from it's ideas when making architectural choices. The one DDD concept that has never worked for me is specifications. I don't see a way to write a specification that could support the wide range of storage options out there. So you always end up with specifications tied your current choice. In other words your persistence layer leaks into your core layer. Even with the EF implementation as presented in this video, which I used in a project some years ago, I felt very limited. With persistence you need to think about performance, scaling, cost, reliability, ... In my personal experience I found that it's impossible to 100% separate persistence from business logic. Either you end up with your persistence layer leaking into your core project, or your business logic leaking into your storage layer. If I have to choose, I prefer the latter. The core is incomplete, but still clean. And you have the full potential of your storage mechanism.
@@Ardalis when you're at the point you have to write a whole new implementation for the specifications, you probably wish you never started with it. You could as well just depend on ef core or hard code them
Open Visual Studio with a DbContext and an entity defined. Right click, Add, New Scaffoled Item, CRUD with DbContext. It will do the rest. It's not loosely-coupled code but it's well-structured and will take you < 5 minutes.
I dont quite understand how moq testing doesn't completely invalidate any concerns about business logic taking a dependency on the data layer. Just write good, mockable interfaces
Specifications are a great idea in theory but nearly impossible to implement with current technology. In your Core project you are not supposed to know anything about persistence. Yet here you are using .Where() and .Include(). This means your persistence layer needs to be able to parse expressions trees for .Where() and .Include() is just a hard dependency on Entity Framework. In conclusion, this implementation requires your core project to have a dependency to EF, and you can only use EF for writing to a database.
It's just the one of the ways of clean architecture. But main idea is same for all of approaches. I think .Net 9 doesn't come any new thing to the clean architecture.
Dunno man, this seems like the most over-engineered shite I have seen in a long time.... I use .Net so I can ship. Not to sit in architecture meetings for weeks. Hard Pass.
I mean, just use the template and follow a couple of relatively simple rules and there's no meetings. You're up and running in about 30 seconds. This isn't some complex kubernetes microservices thing. It's just a monolith that's leaning on the compiler to keep dependencies out of the core business logic. It does that well. Beyond that is up to you.
If you want to overcomplicate things, just follow this "clean architecture" proposal. This guy talks about domain models but includes foreign keys in them (e.g., OrderId), which reflect database relationships but according to him, shouldn’t be there because "the domain does not depend on infrastructure." 😄 Furthermore, even if you only have one concrete implementation of an interface, you’re still required to create an interface-just for the sake of "high level modules should not depend on the low level ones" and unit testing and mocking. But that’s not true because you can mock concrete classes. :) And let’s not even start on the absurdity of DTOs, which, in most cases, look almost identical to the original entity, leading to an unnecessary explosion of DTOs. It’s all just because someone said so, and now it’s become cargo culting.
You can add id properties to entities and they'll work just fine in a document or NoSql db. No foreign key required. As for the rest, use what adds value and skip the rest. It's a popular architecture, and some of that is because folks find it useful, and some of that is probably cargo cult programming (folks who heard it's cool and use it without really understanding it). You'll have some of that (see: microservices) in our industry. I'm not suggesting this is the only way to build or organize software.
>You can add id properties to entities and they'll work just fine in a document or NoSql db. No foreign key required. Why would I go with a NoSql database when my needs fit better with a relational database such as Postgresql? I need to have a CustomerId for my Order domain entity, or an OrderId for the Shipment entity as EF will you use these domain models to map everything to the database. Maybe you want to add another layer for EF to work with, but in this case half of the app would be just mapping 😅
If you're following SOLID principles, clean architecture boils down to an exercise of file reorganization and updating of project dependencies. IMHO, all the unnecessarily complicated terminology (aggregate, adapter, etc.) is just that -- unnecessary complication. I think the big take away is "how I can reorganize my source code to minimize dependencies and improve testability."
Adapter is from Ports and Adapters which is why I mention it. Aggregates are pretty much orthogonal but I think they're helpful and not enough developers know about them so I mention them when I get the chance (which, fair point, maybe overcomplicates the clean architecture discussion).
@@Ardalis It's not a knock on you Steve, it's more of a knock on those creating these architecture patterns. My argument is we can do a better job simplifying things. I've been doing this long enough I know complex solutions are very easy to create and simple solutions are very difficult to create -- including patterns. When I first looked at clean architecture my first reaction is this is way too complicated. I eventually realized it's a pattern using Windows Explorer not Visual Studio if already applying SOLID principles. I tell people I like the clean architecture-ish pattern - the version where I've stripped out all the unnecessary complication where I call an interface an interface and an object mapper an object mapper.
"Clean" architecture is not so clean. There is no simple picture that can explain it correctly. Maybe it has a logical flaw? And of course, CQRS and specification allocation have nothing to do with it, they are just smoke and mirrors.
The picture is, dependencies flow toward the business logic (core, domain model) and away from UI and Infrastructure. It's a pretty simple circle or stacked boxes picture. They (CQRS, specification pattern) are largely unrelated but useful in many scenarios which is why I include/mention them.
@Ardalis You understand that function should do one thing and one thing only? Hiding email sending sooo deep in code, that is already doing another stuff, is bad practice. With another if statement. If I were new team member in this repo, I would neeeever ever have guessed, to search for email sending trigger in db.savechanges.
@@marekjakubicki5795 It's true new team members will need to understand events, and the idea that raised events may have handlers in other parts of the system. This is true in any event driven architecture. This is true in UI/front end development where events are commonplace. And it's true here. "What? When I click this button, the code executes something in a whole different file???"
@@marekjakubicki5795 This is simply how events work. Whether in UI or in Event Driven Architecture, when you do something and it raises an event, you don't really *know* at that point where the event handler(s), if any, are or what they're going to do. You have to go look. This is no different. There are pros and cons to using events, as with any other architectural or pattern choice.
Contents:
01:22 Why Clean Architecture?
02:56 Layered Architectures
08:57 Architecture Tests for Enforcement
09:58 Demo: eShopOnWeb
16:56 How to Organize Code for Clean Architecture
21:11 Demo: Ardalis' Clean Architecture Template sample application
24:20 Demo: Using Ardalis' Clean Architecture Template
26:25 Learn More - which includes all the links to the repos and sites
Thanks!!
Does the clean architecture change in every new version of dotnet? 😂
🤣🤣🤣🤣🤣🤣🤣
Bro asked the real question 😅
ahyahah
New version of .NET comes with new detergent 🧼🧽 formula 😆
Same video have publised a year ago :) ruclips.net/video/yF9SwL0p0Y0/видео.html
And once again this talk is the most popular (non full day stream) talk in the dotnetconf playlist. Say what you will about Clean Architecture, it remains a very popular if sometimes controversial topic...
where is the source code?
Every. Single. Year.
I had some respect for Steve Smith 15 years ago, but after 10 years listening to the same push to "Clean Architecture" it just makes me roll my eyes.
The templated Core project uses a MediatR dependency and injects a MediatR-specific "IMediator _mediator", wouldn't that count as a forbidden infrastructure reference? I understand the events have to be passed somewhere, but would that require a more general infra-agnostic interface?
MediatR is just pure C# code, no dependencies on anything out of process. So, it's fine, IMO.
This is what "Architects" call "We Adopt that to our Architecture" - Sometimes you have to decide for concrete external dependencies, when they serve well, it was a good "adoption" :)
At least once a year I have to watch a video about Clean Archtecture with Jason Taylor and Steve Smith using the current .NET version 😅
I mean, you don't *have* to... Jason and I just met for the first time last month at Techorama Netherlands. He was doing a talk on CA there (and I was not, I had other talks). It was a great presentation and his template is great, too (though I don't care for its direct dependency on EF).
@ is like a classic movie in which you have to revisit every other year, I really like
Nice to know you have meet Jason can we have a collab?
Thanks for you amazing work 🙏🏾
I would prefer having things in ApplicationCore (and maybe other projects) be organized by functionality. Instead of having folders Entities, Exceptions,Interfaces, Services... I'd rather have one folder for one functionality (vertical-slicing approach). This way one quickly sees which functionalities an application is composed of and it's easier to manage when application grows (otherwise lists just get larger and larger, and no one knows which files belong to which functionality).
Agreed 100%. Look for updates to eShopOnWeb along these lines in the future. It has some historical baggage but now that it's maintained by NimblePros I have a freer hand in updating it.
This sounds like a good idea, for sure. Those "service folders" get loaded with tons of files with all sorts of creative naming schemes quite fast..
@@clarkflavor True, it's exactly what layered architecture does and is hated for.
What is the difference between the samples projects and the main projects under root src folder?
edit: I guess I’ll never find out.
UseCases Project?
I saw your Specification library, it has Specification, So I wondering that TResult is the kind of DTO? but the DTO is staying at UseCase layer if I write a kind of generic specification so I have to define the TResult be some base DTO Class? that make Core layer depends on the layer which DTO stayed. How do you think about that usecase Ardalis?
For additional information, I remembered in previous video, in the slide explain what should be put in Core project, the slide showed "DTO". So DTO can be insided "Core"? Or what usecases that should put it there.
Also in the template, I think you should prepare for "Grouping", right now our project based on your template and it missing the grouping in Spec so we have to write an "adapter" to adapt the situation.
Thank you if you have time to read this!
Specifications support projections, which is what TResult is used for. And yes, that would usually be a DTO. I don't typically like to have DTOs in Core but sometimes it's convenient and pragmatism wins over design purity. More typically I might define projection-based specifications in my UseCases layer, which does define DTOs, and that works as well (although then the specifications aren't all in one place, which is a tradeoff as well).
@@Ardalis Please try to reply my question about grouping above, thank you!
I think the example project misses somewhat the point of explaining clean architecture, by explaining how to possible do clean architecture in combination with domain driven design.
actually that is the fucking same shit
All these "Clean Architecture" things look like overengineering for me.
But overall the idea from ports and adapter architecture of separating business logic from everything and making it the core of the system is very useful.
I am actually on Team Jimmy Boggard. Just write everything as simple as possible, with code duplication etc, and then refactor away code smells. You will end up writing your own MediatR (so just start with it), and every handler will be in layers - pull data, modify, save (or more those 3). Unit test the modify, integration test the handler - done.
When you refactor, you will extract shared code into a service - don't start with a service. If you are using EF Core, it already is a repository. If you refactor enough, you will actually get to "DDD but no sweat" - and it's great end goal, not starting point.
That all works, yes, if you're good at refactoring and know what to refactor *to*. If you don't, having some up front rules or policies to follow can be a big help toward ensuring you don't end up in a hole you can't dig out of. Also, the repository pattern is an abstraction that belongs to your domain model, not a concrete implementation that is part of the framework or some third party. Thus, EF Core isn't "a repository" but is a specific persistence library. There's an important difference.
Try using this with something else than Entity Framework. Both specification and domain events are hard-wired to EF. This is not good separation at all.
Both are implementation details. Specifiication has a separate package that provides EF6 or EF Core support. One could add others, or use the library without either ORM if you wanted (though it might be limited to in-memory evaluation at that point so obviously much less useful).
You can implement domain events wherever and however makes sense for you. Doing it post-persistence is a design choice, and having made that choice, tying it directly to SaveChanges(Async) in the DbContext is simply convenient. But changing that would only require a single change.
@@Ardalis Thank you for your reply. I agree with the domain events, personally I would just use something like mediator and call it from a service.
For specifications, it's more difficult. I use clean architecture and I don't use DDD, but I do draw inspiration from it's ideas when making architectural choices. The one DDD concept that has never worked for me is specifications.
I don't see a way to write a specification that could support the wide range of storage options out there. So you always end up with specifications tied your current choice. In other words your persistence layer leaks into your core layer. Even with the EF implementation as presented in this video, which I used in a project some years ago, I felt very limited. With persistence you need to think about performance, scaling, cost, reliability, ...
In my personal experience I found that it's impossible to 100% separate persistence from business logic. Either you end up with your persistence layer leaking into your core project, or your business logic leaking into your storage layer. If I have to choose, I prefer the latter. The core is incomplete, but still clean. And you have the full potential of your storage mechanism.
@@Ardalis when you're at the point you have to write a whole new implementation for the specifications, you probably wish you never started with it. You could as well just depend on ef core or hard code them
I would like to see how to architect a well-structured CRUD. Ultimately, everything ends up with either creating, reading, updating, or deleting.
Open Visual Studio with a DbContext and an entity defined. Right click, Add, New Scaffoled Item, CRUD with DbContext. It will do the rest. It's not loosely-coupled code but it's well-structured and will take you < 5 minutes.
I go by 'ardalis' because there are a lot of Steve Smith! 😂 This line should be in a movie! 😎
Bro calls it hexagonal architecture, and only uses 3 sides. My brother in christ, thats a triangle 😅😅
🤣 *I* didn't invent the name...
I dont quite understand how moq testing doesn't completely invalidate any concerns about business logic taking a dependency on the data layer. Just write good, mockable interfaces
Comment section likes writing N-tier solutions where there are 100 "services" with vague logical coupling... and it shows
Specifications are a great idea in theory but nearly impossible to implement with current technology. In your Core project you are not supposed to know anything about persistence. Yet here you are using .Where() and .Include(). This means your persistence layer needs to be able to parse expressions trees for .Where() and .Include() is just a hard dependency on Entity Framework. In conclusion, this implementation requires your core project to have a dependency to EF, and you can only use EF for writing to a database.
Same year after year. Still something, earlier installing mediatr nuget they used to call the clean architecture
It's just the one of the ways of clean architecture. But main idea is same for all of approaches. I think .Net 9 doesn't come any new thing to the clean architecture.
Mostly just updates to the packages and the addition of aspire, yes.
Dunno man, this seems like the most over-engineered shite I have seen in a long time.... I use .Net so I can ship. Not to sit in architecture meetings for weeks. Hard Pass.
I mean, just use the template and follow a couple of relatively simple rules and there's no meetings. You're up and running in about 30 seconds. This isn't some complex kubernetes microservices thing. It's just a monolith that's leaning on the compiler to keep dependencies out of the core business logic. It does that well. Beyond that is up to you.
What an incredibly sour comment section 😆
If you want to overcomplicate things, just follow this "clean architecture" proposal. This guy talks about domain models but includes foreign keys in them (e.g., OrderId), which reflect database relationships but according to him, shouldn’t be there because "the domain does not depend on infrastructure." 😄 Furthermore, even if you only have one concrete implementation of an interface, you’re still required to create an interface-just for the sake of "high level modules should not depend on the low level ones" and unit testing and mocking. But that’s not true because you can mock concrete classes. :)
And let’s not even start on the absurdity of DTOs, which, in most cases, look almost identical to the original entity, leading to an unnecessary explosion of DTOs. It’s all just because someone said so, and now it’s become cargo culting.
99% of develepers create interfaces for services, repositories anyway, so... ;)
Yeah... backend dev is kinda boring. You can hardly spice it up with some terrible legacy code to make it somewhat interesting 😂😂😂
You can add id properties to entities and they'll work just fine in a document or NoSql db. No foreign key required. As for the rest, use what adds value and skip the rest. It's a popular architecture, and some of that is because folks find it useful, and some of that is probably cargo cult programming (folks who heard it's cool and use it without really understanding it). You'll have some of that (see: microservices) in our industry. I'm not suggesting this is the only way to build or organize software.
>You can add id properties to entities and they'll work just fine in a document or NoSql db. No foreign key required.
Why would I go with a NoSql database when my needs fit better with a relational database such as Postgresql? I need to have a CustomerId for my Order domain entity, or an OrderId for the Shipment entity as EF will you use these domain models to map everything to the database. Maybe you want to add another layer for EF to work with, but in this case half of the app would be just mapping 😅
@@TTNN0 Even if you're using Postgresql, you'll presumably have IDs for related entities somewhere. I think I'm missing your point.
If you're following SOLID principles, clean architecture boils down to an exercise of file reorganization and updating of project dependencies. IMHO, all the unnecessarily complicated terminology (aggregate, adapter, etc.) is just that -- unnecessary complication. I think the big take away is "how I can reorganize my source code to minimize dependencies and improve testability."
Adapter is from Ports and Adapters which is why I mention it. Aggregates are pretty much orthogonal but I think they're helpful and not enough developers know about them so I mention them when I get the chance (which, fair point, maybe overcomplicates the clean architecture discussion).
@@Ardalis It's not a knock on you Steve, it's more of a knock on those creating these architecture patterns. My argument is we can do a better job simplifying things. I've been doing this long enough I know complex solutions are very easy to create and simple solutions are very difficult to create -- including patterns. When I first looked at clean architecture my first reaction is this is way too complicated. I eventually realized it's a pattern using Windows Explorer not Visual Studio if already applying SOLID principles. I tell people I like the clean architecture-ish pattern - the version where I've stripped out all the unnecessary complication where I call an interface an interface and an object mapper an object mapper.
"Clean" architecture is not so clean. There is no simple picture that can explain it correctly. Maybe it has a logical flaw? And of course, CQRS and specification allocation have nothing to do with it, they are just smoke and mirrors.
The picture is, dependencies flow toward the business logic (core, domain model) and away from UI and Infrastructure. It's a pretty simple circle or stacked boxes picture.
They (CQRS, specification pattern) are largely unrelated but useful in many scenarios which is why I include/mention them.
yeah don't burn yourself on this with greenfields, start simpler
old heads with experience only with n-tier won't understand
old heads are and graduate will break this, mark my words
Send e-mail on db save changes? So much of single responsibility...
You understand SRP applies to one class, right? Did you see one class that is responsible for saving changes *and* for sending emails?
@Ardalis You understand that function should do one thing and one thing only? Hiding email sending sooo deep in code, that is already doing another stuff, is bad practice. With another if statement. If I were new team member in this repo, I would neeeever ever have guessed, to search for email sending trigger in db.savechanges.
@@marekjakubicki5795 It's true new team members will need to understand events, and the idea that raised events may have handlers in other parts of the system. This is true in any event driven architecture. This is true in UI/front end development where events are commonplace. And it's true here. "What? When I click this button, the code executes something in a whole different file???"
@@marekjakubicki5795 This is simply how events work. Whether in UI or in Event Driven Architecture, when you do something and it raises an event, you don't really *know* at that point where the event handler(s), if any, are or what they're going to do. You have to go look. This is no different. There are pros and cons to using events, as with any other architectural or pattern choice.
clean architecture 🤮
Clean Arch is over-architect & not really fit for microservices