Clean Architecture in 60 Seconds
58sQuickly explains the core dependency inversion principle in clean architecture, making it easy to understand.
▶ Play ClipDerek Martin from codopinion.com shares his nuanced view on Clean Architecture templates. He explains the core principle of dependency inversion (dependencies pointing inwards) and then critically examines Jason Taylor's popular C# clean architecture template. Derek argues that while the architecture has merit for complex, large applications, templates often lead developers to over-engineer simple apps and miss the real purpose of a rich domain layer.
The core is the domain (business rules), surrounded by use cases (application), then controllers/gateways, and finally external frameworks. The key rule is dependencies point inwards; outer layers can reference inner layers, but not vice-versa.
In Jason Taylor's template, the Domain project contains only entity framework entities (ToDoItem, ToDoList) with no behavior. Derek expects the domain to hold business rules, but the simple 'to-do' example fails to illustrate this important aspect.
The Application project defines an interface 'IApplicationDbContext' but it uses Entity Framework's DbSet types, creating a leaky abstraction. This couples the application layer to EF, contradicting the goal of persistence ignorance.
The template separates controllers, commands, and handlers into different projects based on layers. Derek prefers feature-based organization where related code (controller, command, handler, validator) lives together in one file/folder.
Derek demonstrates consolidating the four projects into two (Web UI + Features). He argues that physical project boundaries are only valuable when you need a hard dependency barrier. For simpler apps, keeping things together improves cohesion and navigability.
Derek concludes that Clean Architecture is a tool, not a rule. He values physical boundaries for complex domains but prefers feature-based organization for simpler applications. The key is understanding your context and not blindly following templates.
"The title is honest: Derek does break down a Clean Architecture example and explicitly states whether he uses it, giving a balanced critique."
What is the fundamental dependency rule in Clean Architecture?
Dependencies point inwards: outer layers can reference inner layers, but inner layers cannot reference outer layers.
01:11
What should the Domain project contain according to Derek?
Business rules, not just entity framework entities. It should be the core of what the application does.
05:09
Why does Derek consider the 'IApplicationDbContext' interface a leaky abstraction?
It uses Entity Framework types (DbSet) in its definition, coupling the Application layer to EF despite claiming persistence ignorance.
06:52
What is Derek's main critique of template-driven Clean Architecture?
Templates are often too simple to illustrate real business rules, leading developers to over-architect small apps without understanding the purpose.
03:11
Dependency Inversion is Key
Clearly explains the core architectural principle that differentiates Clean Architecture from simpler layering.
01:11Domain Should Have Business Rules
Reveals a common misinterpretation of templates where the domain layer is reduced to data entities.
05:09Entity Framework Leaky Abstraction Example
Provides a concrete, critical example of how the template's interface is not truly decoupled from EF.
07:01Controllers Have Low Cohesion
Articulates the trade-off between layer separation and feature cohesion, a key software design tension.
09:42[00:00] hey everybody it's derek martin from
[00:01] codopinion.com a lot of people have
[00:03] asked me directly or indirectly about
[00:05] the clean architecture in my opinion
[00:08] some people have asked me directly and
[00:09] pointed out to jason taylor's c-sharp
[00:11] template while others have asked me
[00:13] indirectly because of the code samples
[00:15] that i have in some of my other videos
[00:16] where i don't apply it so here's my
[00:18] opinion and thoughts on clean
[00:20] architecture templates where i see the
[00:22] value and where i don't so let's cover
[00:24] the clean architecture really quick and
[00:26] just describe this diagram which you've
[00:28] probably seen this is from robert
[00:29] martin's blog in 2012. the very middle
[00:32] is essentially the core is our domain
[00:35] this is where our business rules are
[00:37] outside of that our use cases these are
[00:39] our application how it's invoking those
[00:42] actual
[00:43] domain objects those entities then you
[00:45] have things like controllers if you're
[00:46] doing something like mvc or gateways or
[00:49] presenters for ui but again this is one
[00:52] step further where this is what's
[00:54] actually interacting with calling those
[00:56] use cases and above that is all things
[00:59] external so if you're generally creating
[01:00] a web app this is where the web host is
[01:03] going to live if you're creating a
[01:05] native ui app this is where that ui
[01:08] framework lives but the key thing here
[01:11] are these arrows and these arrows are
[01:14] really pointing inwards that's why i
[01:16] have dependencies point inwards because
[01:17] that's really the key to all of this
[01:19] is that outside layers can reference
[01:22] inside layers but inside layers don't
[01:24] reference outside layers so if you watch
[01:27] my video on coupling specifically
[01:28] talking about afferent and efferent
[01:30] coupling so afrocoupling being who do
[01:32] you depend on in effort coupling being
[01:34] who depends on you
[01:36] is why this is important is because that
[01:37] the very big at the very center here
[01:39] with our domain and our entities
[01:41] who depends on you for afferent coupling
[01:43] well the use cases does
[01:45] who do you depend on efferent coupling
[01:47] nobody nothing is that you don't depend
[01:50] on anything you have no dependencies
[01:51] within entities and as you go out that
[01:54] starts reversing so
[01:56] a lot of this to me and about clean
[01:58] architecture is about dependencies and
[02:00] having that core have no dependencies
[02:03] things depend on it but it does not
[02:05] depend on anything else so a lot of
[02:07] people pointed me to this specific
[02:08] template this is the c-sharp template
[02:10] clean architecture by jason taylor so
[02:12] this is going to what i'm going to use
[02:13] as my example so this is what the actual
[02:15] solution looks like there's four
[02:17] projects application domain
[02:20] infrastructure and web ui so what that
[02:22] looks like from the diagram is the
[02:24] outside here web ui is asp.net core
[02:27] it references infrastructure and
[02:29] application
[02:31] infrastructure is the project that
[02:33] contains like the db context for nad
[02:35] framework and any implementations of any
[02:38] services
[02:40] the application is handlers in commands
[02:43] and queries that's using mediator
[02:46] and then it is referencing the domain
[02:48] and the domain is our entity framework
[02:50] entities so first let's talk about
[02:52] templates for a little bit because i
[02:53] have a love hate relationship with
[02:55] templates and because it falls into the
[02:58] only issues i have with my own code
[02:59] which is providing examples that are
[03:01] simple that people can understand and
[03:02] hopefully the concepts behind it so that
[03:05] they just don't run away with it and
[03:07] keep doing the same thing that they
[03:08] understand their context to see if it
[03:10] actually fits
[03:11] that's the problem i have with templates
[03:13] is that this is a to do list kind of to
[03:17] do item
[03:18] sample that it's using to illustrate
[03:20] this which is super simplistic and
[03:23] exactly i understand this is a template
[03:25] it's an example that's why it is simple
[03:27] but the problem is again people going
[03:29] with this and running wild with this
[03:31] when if you're creating a
[03:33] a smaller type of application do i think
[03:36] you need to do clean architecture no
[03:39] i'll explain why more shortly but i
[03:41] don't think you need to so depending on
[03:43] the size of your app i think there's
[03:45] benefits um to the clean architecture
[03:48] i also think there's a time and a place
[03:50] for it depending on the complexity and
[03:52] the size of your app so what i'm gonna
[03:54] do is go through this template and i'm
[03:56] not criticizing the template so much as
[03:59] i am just trying to explain what i think
[04:01] actually belongs in each project if you
[04:03] have that project again it's this is a
[04:06] template it's a sample so i don't expect
[04:08] it to have a ton of complexity to
[04:10] illustrate really the nuance of why you
[04:12] want clean architecture so the first
[04:14] thing i looked at when i opened this
[04:16] project was this domain project and this
[04:19] is the very center of the core it has no
[04:21] dependencies so it preferences no other
[04:24] projects and when i was looking at it i
[04:26] wanted to see what the if there was if
[04:29] it was doing some aggregates if it had
[04:30] entities whatever the case may be
[04:33] and ultimately what it was is it has
[04:35] this to do item and to-do list
[04:37] which basically are our entity framework
[04:40] entities there's basically no behavior
[04:43] on here at all why would you expect
[04:44] there to be any it's a to do
[04:46] but that's the part where it gets lost
[04:49] is again if people are using this as a
[04:50] template they think oh this is where my
[04:52] entity framework entities go and while
[04:54] it's true that you can have your entity
[04:56] framework entities live in the domain
[04:58] project you can have the infrastructure
[05:00] project which i'll show here has the db
[05:02] context the entity framework db context
[05:04] and it's referencing it and it's using
[05:06] them
[05:07] i would expect my domain project to
[05:09] actually have business rules and again
[05:12] this is a simple example so there are no
[05:14] business rules but my domain project is
[05:17] the core of what my application is it
[05:20] should be the one containing all the
[05:21] business rules this example template
[05:24] displays none of that it illustrates
[05:26] none of that
[05:27] so if you weren't aware of that's the
[05:29] point of the domain in your entities and
[05:31] if you're creating something like
[05:32] aggregates that are consistency boundary
[05:35] check out my video on that
[05:36] that's where this would live but just
[05:38] looking at this template you wouldn't
[05:40] know that all right so the next thing to
[05:42] look at is the application project so
[05:44] this is the one that's referencing the
[05:46] domain so it's a layer above the domain
[05:49] so the things that it has in it that are
[05:52] somewhat interesting i guess in what i
[05:54] like about having kind of this
[05:56] application layer is it's the one that's
[05:58] actually going to invoke and call stuff
[06:00] within your domain so
[06:02] there's this to do items folder and to
[06:04] to-do list folder and it has everything
[06:07] separated for commands queries and event
[06:10] handlers
[06:11] now i'll talk a little bit more about
[06:13] this technical separation later on how i
[06:16] prefer it but i do overall like this
[06:18] approach
[06:19] as you maybe have seen in some of my
[06:21] other videos but one thing i really find
[06:24] interesting is that the application uh
[06:26] this particular project is going to
[06:28] define interfaces just interfaces not
[06:31] the implementation for things that it
[06:32] needs one of those things it needs as
[06:35] you can expect is a
[06:38] entity framework context
[06:40] so instead of referencing the actual db
[06:42] context that's being used directly
[06:44] rather what it interacts with and uses
[06:47] is this eye application db context so
[06:50] the reason why i find this interesting
[06:52] and why i don't generally follow this
[06:54] approach is because of a leaky
[06:56] abstraction
[06:57] and this is showing it whether you
[06:58] realize it or not yet right now so
[07:01] the infrastructure project is what
[07:03] implements all the interfaces defined in
[07:05] the application
[07:07] uh the application project so if i look
[07:09] at infrastructure i go down there is a
[07:11] persistence and application db context
[07:14] so here's our actual entity framework
[07:17] uh db context that we're using
[07:19] and it implements that interface
[07:22] so when i look at that interface the
[07:24] idea here on the application is it is
[07:26] kind of lost on persistence it doesn't
[07:28] really know how it does it doesn't
[07:30] necessarily know that it's entity
[07:31] framework right we just have these lists
[07:34] well actually it does know it's entity
[07:36] framework because it's using these db
[07:38] sets and these db sets are directly
[07:40] coming from entity framework
[07:43] actually this application project has a
[07:46] reference to entity framework so i'll
[07:48] ask you the question if you're going to
[07:50] have a leaky abstraction or you try to
[07:52] want to ignore what your persistence is
[07:54] you're not really doing it with this
[07:56] approach especially how this is anyways
[07:58] so you may be screaming well use the
[08:00] repository pattern i'll save that for
[08:02] another video because that's a whole
[08:03] different topic so i'm all for
[08:05] abstractions the right abstractions and
[08:08] most times i think external services i
[08:10] think are really good to abstract
[08:12] because you can kind of narrow the focus
[08:13] of what that abstraction does and what
[08:15] you need it for but when you're doing
[08:17] something like entity framework or data
[08:19] persistence i think you lose a lot and i
[08:22] generally don't think you actually need
[08:24] it i say that because if you're creating
[08:28] small applications like this or smaller
[08:31] little components which i'll talk about
[08:32] in a minute
[08:34] you don't actually need the abstraction
[08:35] because the actual cost of rewriting
[08:38] where that data access is is so low it
[08:40] wouldn't really even matter you don't
[08:42] even need the abstraction
[08:44] and secondly if you're gonna actually
[08:46] create an abstraction
[08:48] what are you losing by using the direct
[08:51] client or sdk that you're interacting
[08:53] with if you don't have a really narrow
[08:54] focus and you need to use a lot of it
[08:56] then you're just trading more and more
[08:58] into your abstraction to fit it
[09:01] if it's something really critical to you
[09:03] just use it there are exceptions to the
[09:05] rule i mentioned this in other videos
[09:06] messaging libraries give you a lot of
[09:08] functionality that you otherwise
[09:10] wouldn't get from the client or sdk
[09:11] directly that you have to implement
[09:13] yourself so those are the type of
[09:14] distractions that you do want but you're
[09:16] not creating them you don't own them
[09:18] you're using messaging libraries for
[09:19] this all right so the last project to
[09:22] look at is the web ui project so this is
[09:24] the very outer edge this is asp.net core
[09:27] and we have some controllers in here as
[09:28] you might expect so let me jump into the
[09:31] to do items controller
[09:32] and you can see that it has some various
[09:34] actions for kind of crud related things
[09:37] um that we need to interact with for our
[09:39] to-do item now the reason why i don't
[09:42] actually like controllers in general is
[09:44] because they have really low cohesion
[09:47] and especially even more is that um all
[09:49] these particular commands here this
[09:51] create create to do item command
[09:54] this is exactly a one-to-one like this
[09:57] particular action in this controller
[09:59] maps directly to the command and command
[10:02] handler this is the only place at all in
[10:04] solution besides tess
[10:07] that this is actually ever created
[10:09] there's no other place that's creating a
[10:11] to do item there's no other place that's
[10:13] invoking it anywhere calling send on it
[10:15] it's simply here so the reason why i
[10:18] don't like this is because i much prefer
[10:20] having things close together i don't
[10:22] want to have to jump through projects
[10:24] and files i would much rather see
[10:27] everything that belongs together is
[10:29] together and i can go into one location
[10:32] and look at basically everything so when
[10:34] i say group things together i'm
[10:36] generally less concerned about layers
[10:37] for an entire application and more
[10:39] thinking about features and
[10:41] functionality
[10:42] and kind of the concerns within that
[10:44] feature so i'm less concerned about
[10:46] abstractions and i'm more concerned
[10:47] about just what a feature does and
[10:49] letting it define its dependencies and
[10:51] whether it needs an abstraction or not
[10:53] so instead of thinking about the whole
[10:54] layers i'm thinking about what's a
[10:56] particular subset of features and let's
[10:59] pull out the important parts and put all
[11:01] that stuff together so well instead what
[11:04] it really looks like is maybe i have two
[11:06] web ui pieces which are really the
[11:08] controllers that's interacting with say
[11:10] the same infrastructure which maybe
[11:12] could be the certain db context which
[11:15] interacts with our app which is our
[11:17] mediator commands or queries and
[11:19] handlers and maybe those two particular
[11:21] features share a domain but i'm
[11:23] organizing code that way i'm not
[11:25] organizing code necessarily by layers
[11:28] that's happening in that template so
[11:30] taking that concept and consolidating it
[11:32] what this means is i have two projects
[11:34] now not four
[11:36] i have the outermost which is the web ui
[11:38] which is asp.net core and i have to
[11:40] define this as kind of the entry point
[11:42] this could be asp.net core this could be
[11:44] a
[11:45] native ui this could be like a service
[11:47] that's interacting with your your
[11:49] message broker that's going to be
[11:50] invoking into your application this is
[11:52] kind of topmost entry points but i don't
[11:55] actually have any of the controllers
[11:57] here
[11:58] really the controllers are living in
[12:00] their respective features so i now have
[12:02] a folder called features and i have
[12:04] these to-do list items and
[12:06] lists and items
[12:08] and instead of having a file for
[12:12] basically commands and queries like it
[12:14] was earlier and event handlers i left
[12:16] the event handlers in here because they
[12:17] don't really do anything normally these
[12:19] would actually just be a part of this
[12:21] name to what they actually do
[12:23] but if i jump into the create to do item
[12:26] here it has the controller here the web
[12:29] ui is referencing this it's
[12:30] automatically going to pick up this
[12:31] controller i have the relevant mediator
[12:34] command
[12:35] the validator for it and the relevant
[12:37] command handler
[12:39] since it's publishing an event i
[12:41] actually have the event here as well so
[12:44] when i'm talking about or thinking about
[12:45] anything to do with an actual command
[12:48] everything resides in one file it's one
[12:52] place now often the argument is well now
[12:54] you're referencing asp.net core in this
[12:56] application project but it really only
[12:59] needs to be in the web ui true that is
[13:01] true however
[13:03] if you do create some other service if
[13:06] you do
[13:07] that doesn't need asp.net core well yes
[13:10] you will still be referencing it and it
[13:12] just won't do anything that's a price
[13:14] i'm willing to pay to have code that
[13:17] belongs together live together so that i
[13:19] can access it directly and understand
[13:22] instead of jumping through projects and
[13:24] layers i have things closer together so
[13:27] you'll notice i took out that domain
[13:28] project and the reason is is because
[13:30] there was nothing meaningful in it if i
[13:32] was creating a rich domain i did have a
[13:34] lot of complexity around my domain and i
[13:37] wanted to create a separate project so i
[13:39] didn't have any other dependencies that
[13:41] i could focus specifically on that
[13:42] domain to create entities values objects
[13:45] aggregates then yeah that'd be a great
[13:47] idea in this example for illustration
[13:49] purposes there wasn't anything
[13:50] meaningful in it so therefore what's the
[13:52] value of having that project so the
[13:54] value to me in separating by project is
[13:56] if you want a hard physical boundary
[13:59] with dependencies an example of this is
[14:02] that you don't want to accidentally put
[14:04] say some type from asp.net core in a
[14:07] mediator command or query because if you
[14:09] do need to rip that out well now you are
[14:11] actually bound to asp.net core because
[14:13] you have that reference in there in the
[14:15] original template you wouldn't be able
[14:16] to do that so again yes it is about
[14:19] context it is understanding what you're
[14:21] doing and what types you're using where
[14:24] if you want to accomplish that by having
[14:26] the boundaries of projects and layers
[14:29] excellent that more power to you
[14:32] if you can see past that and you
[14:33] actually want to create slices where
[14:35] you're depending less on abstractions
[14:38] and creating smaller units where you can
[14:40] refactor those and pull those out
[14:42] separately then to me there's less of a
[14:44] concern about those abstractions because
[14:46] if you need to replace them what the
[14:48] actual underlying implementation is with
[14:50] something else you can do it so for
[14:52] everybody that's been asking me about
[14:53] this i hope it helps if you found this
[14:55] video helpful give it a thumbs up if you
[14:57] have any thoughts or questions make sure
[14:58] to leave a comment and please subscribe
[15:00] for more videos on software architecture
[15:02] and design thanks
[15:23] you
⚡ Saved you 0h 15m reading this? Transcribe any YouTube video for free — no signup needed.