This is one of my favorite videos of yours so far! The patterns demonstrated in the Clean Architecture sample that you showed are all too familiar, and I've tried in the past to get people to see why this is an issue. There are so many things to change when any use case changes, and it's super easy to miss something. It's unfortunate that so many people still cling to this file structure.
Thanks. This was talk I did recently at a conference so I decided to just record it. Really it's a collection of videos I've done in the past just mashed up together.
I feel validated by this video haha. I've had this discussion and demonstrated the separation of concerns alongside cohesion to many colleagues and I'm astounded how many are perplexed by the idea because "it doesn't follow the known patterns." Thanks for sharing this video!
In the past 3 weeks we’ve merged 4 micro services using clean architecture back into one of our main projects. We’ve started removing the clean architecture layers from those projects that have been merged in where it makes sense to. We are amazed at the results! We have gotten rid of so much superfluous code! We generally have 5x less code/files. The code is so much simpler (and cleaner, funny enough). It’s easier to find the places where to refactor… the clean architecture was hiding many places where we could improve our code. And the benefits of removing unneeded micro services has also removed superfluous connecting code. It’s been great! What seemed like an unmanageable nightmare now seems like it can be tamed and is now enjoyable to work with again.
@@cicerofoscarini8890 we’re a small team of 4 devs and a couple of external contributors. Usually there’s either one or two devs working on each project. Should never have gone down the micro services route as our team was too small to support it effectively.
And that is exactly why this makes sense. Too many people are implementing without actually understanding why they are doing it. KISS is appropriate everywhere, or to use Einstein's methodology, "Everything should be made as simple as possible, but not simpler.". I think he captured it well.
Sounds like a decent decision. However please remember to update again here in 12 months id be curious to see how it pans out in the long term. There arent often golden bullets just different sets of problems and tradeoffs so will be interesting if you hit different issues.
Awesome content! This is the best video about layer architecture I have seen lately. I believe people create templates with this module structure to enforce the prevention of compiling a module with a wrongly directed import statement.
Why not organize first into features, then layers? The problem with not making layers visible in the project structure is, that in a team with different skill levels present I'd say it is almost impossible to keep any unobvious layer concept intact over time. So you WILL end up with domain logic coupled to infrastructure and application concerns.
First off, thank you for rounding it all up in one video, I will spread it as far as I can, with this channel you're doing the code better! Could you make an addition to this video with practical examples? I still have so many questions on what do you do when you need to communicate between features, or creating a feature that depends on multiple feature, or how do you share the same model across multiple features? Thanks again!
Excellent explanation of something which should be interviewed for during every IT job interview, in my opinion, to filter out the pattern-as-dogma-crowd.
The analogy to a recipe is perfect. Not everytime we need to do surgeries. We can do them sometimes in different zones. Not in the whole body. Thanks for the amazing info and knowledge share. World gets better when we know what to do for us and clients.
Great material. 😃 Looking back at the projects I've been involved in. I am also having similar thoughts. I generally agree with this approach. However, it is important to remember that the entire team should have a similar level of knowledge/understanding of the subject. Especially people who are new to join such a project.
We use this organization structure at work. One thing that can really help, especially with juniors, is something like ArchUnit (this is for Java). It helps to validate architecture, such as guaranteeing certain packages don't reference other packages, or even that certain named classes don't reference certain packages. We have standard naming for standard purpose classes (e.g. *Repository, *Service, *Request, *Controller, etc), so we also make sure a class doesn't contain that standard name in the wrong package, or a standard name doesn't reference the wrong layer. E.g. *Service shouldn't access *Controller. This can be especially beneficial if you don't further divide things up in a vertical slice.
That sounds very useful, I was worried about how to enforce the architecture and had never heard of packages that serve that purpose. Thanks for sharing!
There are always tradeoffs. The trouble with monolithic code patterns is that you often find similar usages across the vertical layers that require you either to couple one tower to another or else result in code being replicated across towers. I have seen the results of this pattern of not having a single idea of a product across business domains, and you end up with massive code replication and systems breaking routinely in production because one team subtly changed its definitions and business logic and this impacted other systems but was not caught in testing. The number of test cases that have to be written vastly increases and so forth. In a real sense people are just pendulum swinging back and forth between different design patterns and as they get more familiar with one they start getting grass is greener on the other side issues, and start longing for patterns that were previously abandoned.
Whatever structure you go with, you still have to have a single representation of a determined concept in your code. In vertical slicing, what stops you to have kind of a "core" package that shared smilar code ?
You don't have to replicate the code; just extract it into another module and use that module everywhere it's used. And it should be sufficiently uncoupled with the modules using it to avoid future refactoring, just as its identical implementation in a layer would be. The only difference is now you're calling the layer in each module that needs it from within that module, rather than on all modules unconditionally.
nice new perspective in structuring... the cake slices example and they way explained cohesion with it... so beautiful. it really makes sense. wonderful
Great video, awesome points and I mostly agree with all Clean Arch presented concepts! I do have a point to add though, the dependency direction/coupling of the project exemplified at 5:44 seems wrong (or confusing) to me according to the Clean Architecture book's concepts (unless the Infrastructure layer shown is an Adapter layer called Infrastructure and not the real Infra layer which would be coupled with a specific tech choice). That is, in my understanding, WebUI (blue layer/external layer/frameworks) must not reference an "infrastructure" layer (which should be blue, not green, cause it's also an external layer... the green layer is an adapter to the infrastructure where you must invert the dependency direction (DI)). A "purist" (by concept) clean architecture in this example (IMHO) would go: WebUI ->| Application -> | Domain _________| Application (I)|
Just realized that GraphQL is CQRS by design (query and mutation). And using Apollo Federation and extending shared types is a way of slicing a common schema model and allowing each business area to add their specific view about e.g. a "Product", which is a cohesive architecture pattern by design. The only way to mess up coupling at that point is shared libraries which may still add coupling between different business areas.
😮 where has this video been all my life? I've just spun up another service using clean architecture in the classic form....thank goodness I've caught this early!
Excellent explanation of the concepts. Many of your points about the creation of turds I have seen created over time. The importance of the different contexts against the same data is critically important. Excellent video!
Such a convoluted solution for a non-problem. The motivation for vertical slices is always having to dig through folders to get all the files for an entity/feature. Whenever I find myself doing this in layered architectures, I just use my editor to search for the filenames that contain the entity name and then open those. Problem solved.
Not really. What is the size of your codebase? How many different domains are mixed there? Do you need to migrate some of them at a time, or everything applies to all of them at once?
It’s not actually a full vertical slice. In your example you are only slicing up the application layer but still leave other layers (i.e. infrastructure). Most examples I have seen also do this, but they don’t achieve what the commonly used image actually displays (slicing UI, application, domain and infrastructure). Thus, you still end up with layered architecture in the end. However, if you were to be consistent with the slice, that would mean plenty of code duplication, for instance, repositories would be sliced across features, and so forth, and that is not ideal.
"repositories would be sliced across features, and so forth, and that is not ideal" Sometimes it's ideal, sometimes it's not. Sometimes features use different repository methods making it pointless to share. Sometimes repository methods try to do too much to serve the features that share it making it bloated and inefficient. One feature might need 2 pieces of order related data from one data source, another might need 50 across multiple data sources. I always start by putting my repositories in the slices and then as the feature set grows I pull out what makes sense to share and leave the rest. If the shared resource gets bloated later on, I break it up to the slice level.
@@bike4aday I feel like there is a lot of exploratory work involved in Vertical slice architecture and we are still "getting to know it". There are also mixed opinions and criteria of what should or shouldn't be the case with these. For example, if we dogmatically did it, with maximum feature isolation which does not leak out to other features, like in article "Out With the Onion, in with Vertical Slices", we also end up with *funny* things like css and FE code along with all other BE code.
You aren't going to have a DbContext per request. Nor would you have an aggregate per.. It would be for a feature set. The point isn't share nothing. It's putting related things as close together as possible.
I find the distinction easy to make. Business processes/operations are self contained - they are the slice. Loading data for a slice is part of that business process. 2 processes loading “the same” data is just coincidence. I won’t go too much into the pointlessness of using repositories with EF core ;) “Infrastructure” is shared code. It has nothing to do with the business problem you are trying to solve. It is utility/convenience. e.g a “GitHubClient” which essentially wraps an “HttpClient” and exposes some specific methods to interact with GitHub/some 3rd party API
@@kabal911 It actually typically has a lot to do with the problem you are trying to solve, for example, Order entity is an infrastructure piece (DB/ORM). Same goes for Order router. Probably rather than using infrastructure which confuses things it’s better to use “shared”
Separating by project/dll/package, is more about independant delivery/deployment and also team dependency, so it's better to separate by project/dll/package, trying to reason in terms of Dependency Inversion Principle (from SOLID) as suggested by Clean or Hexagonal Architecture. It's about seeing deliveries as PLUGINs for an independant package.
I think that a good way to think about coupling and cohesion may be the opposite as everyone does. A single unit may have low cohesion (lot of responsibilities) but it has 0 coupling by definition because it cannot be coupled to itself. When you split that thing in two to make it more cohesive, now you got coupling. That means that splitting things increases coupling and cohesion so they are opposite forces. It's an art to win in this situation and applying prescribed solutions doesn't help. Also I see a lot of people that think that the mere act of splitting things reduces coupling when it's actually the opposite (e.g.: Microservices)
Great video, great presentation. Something was screaming "bounded context" at the back of my head all the time, though. Your "features" are a level of granularity lower, but the example of "product" meaning different things to different users is how I understand "bounded context". Two use cases may be talking about the same physical entity but each views and handles it in their context, using their vocabulary and their features.
@@CodeOpinion was great! Though it raises a few questions. If you do sliced architecture and need some background jobs like azure functions. How we do it is sharing libraries between the api and the function app to make sure both are deployed in case of underlaying changes. In those cases we actually end up with some middleground where we make a Core library that has shared data models and infrastructure to avoid having to duplicate models and forget to make changes. I'm also interested to see how a VSA would look without MediatR. I guess you would end up building something similar? When you put controllers in same file sliced out, how do you deal with shared routing eg. api/products... do you put that as static constants? Have you tried using minimal apis with this approach or the nuget FastEndpoints? I'm also all for putting multiple classes in the same file. This is common when doing frontend do why cant we do it in backend? :) i have managed to change the mind of one in my team, so now we do it hehe
One of the biggest advantages of layer architecture is that you can control what you expose to the next layer and also prevent spaghetti code. With just vertical slice, it's really hard to enforce decoupling and when working with a large team of developers people are going to mess things up. One idea I have in mind is having a Clean/Layer architecture and each layer is a separate vertical, trying to merge the benefits of both ideas
I had the same experience. Working with folder structures and in a pragmatic way was extremely difficult with large teams or teams with not enought seniority. In the end you need silver bullets for everything. Many projects to avoid coupling at compile time , mediatR to avoid fat controllers, even microservices just for damage control the devs etc etc. Having said that... great video @CodeOpinion , love your work.
Not wanting to take away from what has been shared because it's awesome, as ever. As the video identifies, there is some value in cohesion along horizontals too. The domain is an obvious one, but the API can benefit too: HATEOAS is a love letter to cohesion across the top of the stack.
What about same application code being used by API, or gRPC or WPF forms should we put all of those “presentation” classes together? I mostly agree except with having the controller class bundled together.
This would exactly be the reason to have those in separate projects. Projects/assemblies are exactly for this purpose, reuse. So ya, don't put frontend with the rest of it.
I think this might be your best video yet. It provides a lot of context to how you think about architecture that isn't always clear in the shorter videos. I think a lot of those will make even more sense if I re-watch them after having watched this one. This is way more than just a video about project re-organization. It's about a better way of tackling problems (features) such that you use the best code for the job. Don't create a domain layer for a simple feature that only needs crud. Doing so will be the equivalent of wearing snowshoes in summer. You can still get around, but it's going to be longer and more complicated than without them. Likewise, using CRUD for a feature with complex business rules is like walking through deep snow in just your sneakers. You're going to fall down a lot. Anyway, great job. Super helpful!
Ya, this video is really a combination of a bunch of videos that I've already done. Just makes the whole concept in a more cohesive (pun-intended) video.
1) This argument is somewhat similar to Uncle Bob's one, "screaming architecture", discussed in its book "Clean Architecture" 2) Using different projects in .NET enforces the acyclic dependencies principle, i.e., you cannot create circular dependencies. Without this division, you have to use tools like NetArchTest to have the same feature 3) For Web APIs, it is possible to use the REPR pattern (e.g. in .NET, Ardalis ApiEndpoints or FastEndpoints NuGet packages) to favor a cohesive structure of the files 4) The example of a product, discussed in the Informational and functional cohesion section, has been covered in detail in Mauro Servienti's talk "All our aggregates are wrong" Thank you very much for your clear and thorough explanation! I prefer this longer format. p.s. I'd really like to see a video with a list of recommended books!
*2) Using different projects in .NET enforces the acyclic dependencies principle, i.e., you cannot create circular dependencies. Without this division, you have to use tools like NetArchTest to have the same feature* I've inherited a few projects over the years where this is most definitely not the case.
For anyone in the Node world and don't know NestJS, it has a wonderful ability to slice the onion so that you can build modules of feature functionality, which are like mini-onions. Very powerful!!!
The whole onion architecture is basically intended in the Node backend world with the request context being passed through a series of middleware functions. It's trivial to keep the style going from the middleware to the actual endpoint functions if you use typescript decorators, since they're just functions that wrap the function they annotate and are executed in the same order they're written. So you can have @Authorize @Validate @Whatever endpointFunction() { ... }, and it'll run authorization, then validation, then whatever and then the function.
Thanks, Derek, very interesting video. I have a question, though. What happens when you have multiple clients that have the same feature but that show different data? For example, you could have a SPA, an MVC app and a mobile app that all need to display different item data. How do you do this? Typically I see people returning the full data with all the fields for each one, but if you only wanted to return the necessary data for each how would you achieve that? Would you add query parameters to the endpoint that specify which fields you need? But what happens if one of these clients need the items to be joined with another table/entity for additional data? I haven't yet found a good solution for this.
You're getting into BFF (Backend for Frontend) concepts with this and view/ui composition. I haven't done one exactly on this, but have talked a bit about it in here: ua-cam.com/video/ILbjKR1FXoc/v-deo.html
I don’t see how this is really different to “traditional” architecture. You would still need separate/different endpoints if your REALLY wanted to support different data shapes. The problem is not the code organization, but the endpoints/REST. This is ultimately what something like graphql tries to solve.
Amazing video and concise examples, nice work! This is a common topic and all because IDEs don't allow the creation of tags and scopes for project structure visualization. I'm currently working on an extension that allows you to create your own project layout views using annotations. Then arrange your code and files as u want ;)😉
I wrote a Blazor app for work a few years ago and followed the Clean Architecture structure. I've been on the hunt for a good way of structuring apps for years, and I tried it out for this app. As I was developing it, it kinda made sense. Then I deployed the app and went away for a while, doing other work. Then I had some change requests and bug fixes for the app. And looking at it now, it is a complete mess! Exactly as you describe here - files in so many different places across several projects, so making a simple change can involve changing ten different files. At some point, I'm definitely going to rebuild the app and base it on a much simpler structure. VSA might well work for that. It'll certainly be a lot better than what I have now!
Yes yes and yes. Started my first job as a junior feeling ready to make some nice layered code with nice abstractions and it looked awesome when i was done with the initial codebase, only to absolutely hate whenever people asked for new features / changes, because i had lost the overview. I was afraid of changing stuff as the use cases changed Lately i've been grouping stuff based on ownership even if that called for some duplicate code here and there, but it guaranteed me i knew what would be affected whenever i went in to make changes.
when using a single database, is it worth splitting the domain into smaller ones for each function, or is it worth using one super-domain project with a description of all entities? for example, if there are about two hundred related tables, when updating one of them, there will be a lot of work when updating its entity locally for each function. What is the best thing to do?
With a legacy solution, a layered monolith, how would the vertical slices be introduced into the same monolithic solution without fitting it into existing (non-clean) layers? Maybe a new project? Then vertical slices within that same project? Or a separate project or set of projects from each slice?
I love the way you say "I'm not that way" .. its kind of implying that people with "those" beliefs are somehow misguided, but you're not making a value judgement out of politeness/repect
This is all fine and dandy, and you make some good points, points I wish more 'legacy' companies would consider when hiring people who actually WANT to make the systems architecture cleaner. Unfortunately, the reality is many legacy companies (perhaps not the kind your example shows) operate on a "let's put all our business logic in the database, but never document it or track changes" mentality. This completely nullifies and obliterates any sensible architectural concerns (not saying MVC is good architecture, quite the opposite, but at least it can be refactored and tracked by subversion). TLDR: Document your SQL in some way, or resign as a developer. I'm tired of having to guess what your complicated storedproc does because you spew a bunch of CAST()s and SUBSTING() without actually naming your variables (especially table aliases) something sensible and self-documenting.
There's also the "SQL is the way, the truth and the life" mentality, which is retarded.... there ARE other dbs out there and not all of them are trendy toys like MongoDB (Cassandra, Redis, and Neo4j are all exceptional at their jobs, yet I keep landing contracts with everything being stuffed into SQL Server like it's the 1970's)
Grouping classes (that belong to one layer) in a single package, module or project has always been counter-intuitive for me. Just because a class has the "Controller" or the "Activity" in its name (as a suffix usually) doesn't mean you have to put all the controllers in the same holder (i.e. folder), as these classes have very little or nothing in common. Instead, breaking down the application into the features (rather than layers) and then designing every feature as a single component/service, which contains many cohesive sub-components/classes, is a much more flexible architecture, if you later decide to, let's say, extract one feature as a micro-service or simply replace the libraries for event handling, messaging or even introduce a new DB. I am very happy this video recommends/approves this very same approach,. One more thing, working on my bachelor thesis (ages ago...), named "The Cohesion in OOP", helped me to question the "layered" approach from the very beginning even though I had a very limited experience in software/code design, so I think it is very important to cover (or at least get familiar with) the theoretical aspects of the software engineering. It certainly helps (from my experience) to recognize and avoid the scenarios that could give you troubles in the future.
Great video with a lot of detail. But, one file having the whole slice/feature in with potentially 100s or 1000s of line long sound terrible, most likely would have regions all over it. One reason why layered/clean architecture is so popular is everyone knows it and understands it, when working with external developers this is beneficial as its something everyone can relate to.
Introducing and selling vertical slicing is not too hard in my experience. Developers get it instantly, including external developers and fresh from college juniors. The benefit of not having any significant merge conflicts when working in parallel (feature/developer) is a big selling point. Other architects are harder to convince, like always.
Great video! How do you feel about VSA on the frontend? I'm currently researching how to scale large frontend applications using design patterns, but a lot of resources only talk about the backend.
I’ve followed vertical slice architecture on a very large project (with the nested class for naming) - one thing we don’t do is the controller per feature which is an interesting idea. We have a partial controller for each entity, with a another partial for the actual feature route. I think I like your way. Not sure what impact it would be moving from 10 controllers with around 500 actions, to 500 controllers?
At 8:11 would be really helpful for random access viewers to label bottom as “business domain” … one of these is not like the other. (If that’s the case, not an msft person)
At first specifications looks nice but then you realize they are a very limited overhead over a dbContext that is already an abstraction of the database. I loved how you grouped your features and files with multiple classes per file.
thank you for this explanation, but I had some thoughts in my mind regarding this as I know clean architecture is not just meant for cohesion but also meant for isolation between business logic and infrastructure, in clean architecture you need to build some sort of abstraction layer using facades and adapters to avoid technology changes, so for example if you wanted to change the database, you can build the actual implementation that matches the adapter layer and here you go you changed your infrastructure without affecting other important areas, but in vertical slice architecture, while you are grouping related things together, if you wanted to change your db to another one, how much change should be done?
The only thing that overthinking architecture ever did for anyone is get solutions stuck in a dependency catch-22 What software architecture has taught me over the past 20 years is that software architects are addicted to solving non-problems. In compiled DLL languages these problems that we are trying to solve are basically build into the DLL model itself. Basically projects: the architect’s favorite folder. Completely made up doctrines like no upstream dependencies are primarily due to how compiled languages have separate DLLs requiring each over instead of just compiling the gdámn executables from the various dependencies. The no-circular referencing of BLs is an OOP problem, to which the solution was always staring us in the face: less architecture, not more. Functions, not BLs. The BL itself is a failure to do the basics right in the first place. KISS and separation of concerns. The BL is itself an encapsulation of concerns, but a function isn’t. A function can have a dependency on another function that has a dependency right back on itself, and it’s fine. We even gave it a fancy word. These same original DLL and BL problems just keep getting more and more fancy ways of solving the same self inflicted problems of too much architecture and not getting the basics right. What do we do when one rigid BL needs to call another rigid BL that itself depends on that other one? We pull that functionality out unto a less rigid “helper”. And those helpers are just functions. See what we did there? Now just take that same idea to the limit and get rid of the rest of the artificial, self-inflicted rigidity, and all of these fárt-sniffing solutions to the same old problems we created for ourselves go away, by OBEYing the fundamentals of software architecture. 1) KISS 2) SoC Do these two things and vertical slices becomes an eldritch solution to a problem that no longer exists. Then compile your in-house code to a (A) dll, and your upstream/downstream solutions become a “wtf are you talking about? What is upstream mean?” It means that architects treat projects like folders, but to be fair, these problems are baked into the project based OOP programming models themselves.
Yes!!! nothing wrong with multiple classes in a file, had discussions on it... i like my interface right above my class in the same file. If i have 2 implementations of an IStorageService, one for local file storage and the other for writing an reading from a blobstorage, i like them in the same file. So glad i am not alone on this.
Your controllers should handle only the HTTP request-response cycle. Such as receiving inputs, calling services and return responses like succes or error messages. Your logic should be handled through a Service layer which get called in your controller. This is done for many reasons: - Reusable: for example a UserService.EditUser(..) function can be called inside the ProfileController for users and inside AdminController for admins. - Maintainability: If changes happen you only change the Service function and both controller endpoints will work right out of the gate. - Testability: simulating HTTP requests to hit your controller endpoints during testing is annoying and difficult. It is much better to instantiate the service class, execute the function and then test it. - Scalability: as your app grows you won’t lead to code inertia where it’s difficult to change or add new features. This separation will keep you to ship rapidly. MediatR is excellent for keeping controller functions at max 3 - 4 lines of code and transfer all your business logic to separate Service layers
One of the best, I would not say video but guide, arround Internet about SW Architecture. You touched some wounds over here (like, c'mon.... have you ever read the name of the channel?).
Can you make a video? Over migration from relational to no sql. Taking reference of schema you shown at 23:00. What need to taken care. When need to embed, when we should go for relationship etc. I would love hear those key points.
Thank's for this Derek. Is there a template such as the one for Clean Architecture for this approach? It's always much easier to start doing stuff in a different way when there's an example how this is done. If the template gains popularity people will most probably be willing to contribute to keep it up to date.
22:20 i would prefer not to put everything in one file and rather make separate files in the same folder why? because i dont like scrolling, and when i open a file i wanna see the thing it does. i also place shorter functions/methods higher than the longer ones so i can see many thing without scrolling so much. and time to time i open stuff next to next on the IDE and its not possible or hard if they are in the same file. i also dont like nesting stuff into multiple folders deep, but i would just put everything into their own file in the same folder
@CodeOpinion may I suggest this is very much the idea (loosely) of how Unix handles things via scripting together a bunch of relatively simple utilities: not all of them have I/O other than standard I/O and stderr, nor do they need to: they may instead set the system to a particular state instead as they have data filtered through them, or any other arbitrary number of things. It’s true, it’s not a perfect analogy. When building up complex systems of scripted components like this in processing pipelines, it’s easiest to do it incrementally along the way. Ultimately an “application” is just a bunch of simpler processes chained via the script. I’ve for many years considered this is likely a better way to do things within a single process instead of the Unix method (or using PowerShell, which is more OO) of composition by smaller programs. I’d suggest a great advantage of doing things with these smaller vertical slices however it is done, is it isn’t as painful to obliterate something you wish to remove or replace, in all aspects: all code is easier to delete, and code that is easier to delete is easier to perfect, where the ultimate perfection is no code at all: that’s one bit of code you can be sure won’t be buggy 😉
Wonderful video! I love it. I have a question. If I share a model between features, I share property and behaviour that don't interest all the feature. Is there a way to solve it? Example a shared basic model only with SKU property and treats with property and method, in this way I can share logic, I can build custom model for each feature. The same for repo. I don't delete method available on update feature. (I understand tha I can execute a simple query instead a orm function.) Is this a good way in your opinion?
You don't have to have a "model" that's shared at all if you want to simply use a transaction script. I only suggest it if you don't have consistency concerns and it's really just a data model. At that point your transaction scripts are implementing the behavior. If you do have a lot of logic, complexity, and need consistency, then stick to an aggregate. Check out: ua-cam.com/video/aLFMJ_frafg/v-deo.html
Loved this video, I think this is a really underrated topic. I'm not sure I agree with the framing that increasing cohesion increases coupling and vice versa. Take the reddit guy's data model as an example. If you were to stick whatever that app is into a typical layered structure but without some kind of vertical/feature slicing, you would end up with a ton of coupling caused by the center of the layers having very little separation of concerns. All the features would be extremely brittle to change in one another. This feels like coupling to me. I think maybe a more accurate framing is that high cohesion creates greater local coupling in exchange for the benefit of lower project-wide coupling. The intra-feature bits that do cohere with one another will be slightly more coupled - which costs much less because of their natural relatedness - but the rest of the project becomes significantly less coupled to each individual feature, which is a far more expensive kind of coupling. Curious what you think about that.
Very nice video with a clean explanation, I like it. However, one thing still bothers me; why did you put the controller into the vertical slice? Shouldn't it be at the edge, like persistence? Or another way around, shouldn't you also put the persistence into the same vertical slice?
Persistence was shared several requests, hence why it was directly in the same file. The controller with the single route was in the same file because it's specific for that request.
Interesting one. Do you think, we should have seperate projects for logical concerns, rather than projects split into clean structure like adding domain, application etc? Could these be folders in a single project, for vertical slice?
You can, but you don't have to. Projects are often just use as a physical barriers or to prevent circular referencing. You don't need multiple projects at all. You can just use a folder structure within a single project. All depends on what your needs are.
How do you do domain validation in a reusable way within this architecture? This would be outside of your normal validation making sure this is a valid email. Something along the lines of ensuring the email is unique or more complex scenarios where you have to do a DB call to validate this is a valid action given the persisted settings.
If the UI is within the same platform, then next to it. For exmaple, if you're talking about MVC, all of them can be organized in code together. If you had a iOS app and a .NET Backend, that code won't live together from a development view, but it it is from a logical view.
Excellent video Derek! I still have lots of question regarding Vertical Slices, but I'm getting to it... What's your opinion regarding that issue: Let's say I have a use case that involves 4 changes to the database on 4 different Services, one depending on the other to get the ID for example. These changes are within methods and they call other repository methods. How can I mitigate issues if something fails between one update and another? Rollback is not an option since I am working with different Contexts.
So vertical slices is about expressing the "virtual" vertical slices across a layered architecture. My problem is that even you go great lengths to create vertical slice at some point the slices will share functionality with other slices. Excellent example is authentication and authorization, the functionality is the same for all slices. If you plug it into all or most slices it becomes a layer. At the end you do not want to directly depend on the data persistence solution, so you will build an interface and implement a service. Slices without interacting with the domain are the definition of services?
Great video, it's a great structure for larger projects. I'm having one issue though, and I can't find where in my configuration I'm doing this wrong - When Nesting the items under a static class (22min in), it all works EXCEPT for the controller. As soon as I put the controller inside the static class, it fails to find and expose it. Any tips on making this work?
Always great. But I have a non related question, my work experience is 10+ years. Now I want to become an architect. What will be starting point and path for me? Please suggest. Thank you!
Good points. But if these layers aren't physical separated, you will have people start directly referencing infrastructure code in your UI code. Then we're back to the 90's. There's nothing wrong with that, if your app is small. That ☯️ thing explains it all. It's a balance and it depends.
Hey Derek Thank you for the great content, i was messing around vertical slice arch for a while now and i really enjoying it. But there a question, if the controller and command and command handler are basically in the same file why do we need mediator then?
Something like MediatR separates ASP.NET Core from your application code. You're converting an HTTP request into an application request. You don't need MediatR to do this, but it forces the concept. However, if you were to put HttpContext or anything ASP.NET Core into your requests, you're losing some of the purpose. I find the true benefit if you're creating a request pipeline for your application (mediatr) request. There are other libraries that do this beyond mediator that also work out of process (wolverine, brighter, etc).
My Tech Lead recommended me this channel and gotta say you immediately earned a new sub🦾 Great video really. I have read about similar dicussion about Cohesion and Coupling from the Modern Software Engineering Book and I got to say spot on your thought process!
Multiple classes in the same file is code smell to me, even if IDE's allow you to find it. It makes it harder to modify than necessary when you don't have it collapsed when scrolling around... Especially if they have similar looking code. There's a reason why classes are per file. I agree with DDD though and organizing by logical/feature-based layers. Microservice architectures basically lend themselves to this design strategy.
I would like to know your opinion on how you would deal with the following scenario. Let's say we have an API project where we implemented features using Vertical Slice Architecture. All these features(slices) are implemented in the Features folder using the illustrated pattern from the video. Now we decided to have Blazor Webassembly as our frontend and we would like to reuse requests and responses(commands/queries) from the API project. What would be the most appropriate way to share these requests and responses? Would it be okay to create a DLL library(contracts) that would mirror our Features folder from the API project and declare there only requests and responses(commands/queries) and then we would reference this DLL from both API and Blazor projects? With this approach, it would be theoretically enough then to implement those queries/commands in the API project and we should be able to reuse the same code between the frontend and backend. Or is there any better approach for this kind of code sharing? Thank you
This is one of my favorite videos of yours so far! The patterns demonstrated in the Clean Architecture sample that you showed are all too familiar, and I've tried in the past to get people to see why this is an issue. There are so many things to change when any use case changes, and it's super easy to miss something. It's unfortunate that so many people still cling to this file structure.
Thanks. This was talk I did recently at a conference so I decided to just record it. Really it's a collection of videos I've done in the past just mashed up together.
I feel validated by this video haha. I've had this discussion and demonstrated the separation of concerns alongside cohesion to many colleagues and I'm astounded how many are perplexed by the idea because "it doesn't follow the known patterns." Thanks for sharing this video!
In the past 3 weeks we’ve merged 4 micro services using clean architecture back into one of our main projects. We’ve started removing the clean architecture layers from those projects that have been merged in where it makes sense to. We are amazed at the results! We have gotten rid of so much superfluous code! We generally have 5x less code/files. The code is so much simpler (and cleaner, funny enough). It’s easier to find the places where to refactor… the clean architecture was hiding many places where we could improve our code. And the benefits of removing unneeded micro services has also removed superfluous connecting code. It’s been great! What seemed like an unmanageable nightmare now seems like it can be tamed and is now enjoyable to work with again.
How many people are working on each project?
@@cicerofoscarini8890 we’re a small team of 4 devs and a couple of external contributors. Usually there’s either one or two devs working on each project. Should never have gone down the micro services route as our team was too small to support it effectively.
Sounds like a monorepo was a better choice.
And that is exactly why this makes sense. Too many people are implementing without actually understanding why they are doing it. KISS is appropriate everywhere, or to use Einstein's methodology, "Everything should be made as simple as possible, but not simpler.". I think he captured it well.
Sounds like a decent decision. However please remember to update again here in 12 months id be curious to see how it pans out in the long term. There arent often golden bullets just different sets of problems and tradeoffs so will be interesting if you hit different issues.
Loved this video format with longer length, detailed content and nice pace. By far the best video of the channel so far.
Thanks. It really a bunch of previous videos mashed into one. Don't tell anyone 😂
Awesome content!
This is the best video about layer architecture I have seen lately. I believe people create templates with this module structure to enforce the prevention of compiling a module with a wrongly directed import statement.
Why not organize first into features, then layers? The problem with not making layers visible in the project structure is, that in a team with different skill levels present I'd say it is almost impossible to keep any unobvious layer concept intact over time. So you WILL end up with domain logic coupled to infrastructure and application concerns.
That's what code reviews and peer reviews should take care off 🤔
@@MiningForPies and architectural tests
First off, thank you for rounding it all up in one video, I will spread it as far as I can, with this channel you're doing the code better! Could you make an addition to this video with practical examples? I still have so many questions on what do you do when you need to communicate between features, or creating a feature that depends on multiple feature, or how do you share the same model across multiple features? Thanks again!
Yes, I'll likely create something in the future to better illustrate
Excellent explanation of something which should be interviewed for during every IT job interview, in my opinion, to filter out the pattern-as-dogma-crowd.
The analogy to a recipe is perfect. Not everytime we need to do surgeries. We can do them sometimes in different zones. Not in the whole body.
Thanks for the amazing info and knowledge share. World gets better when we know what to do for us and clients.
Thanks!
Thank you!
Great material. 😃 Looking back at the projects I've been involved in. I am also having similar thoughts.
I generally agree with this approach. However, it is important to remember that the entire team should have a similar level of knowledge/understanding of the subject. Especially people who are new to join such a project.
Yes. If people heavy into with layer by project, it can be a bit of a change.
We use this organization structure at work.
One thing that can really help, especially with juniors, is something like ArchUnit (this is for Java). It helps to validate architecture, such as guaranteeing certain packages don't reference other packages, or even that certain named classes don't reference certain packages.
We have standard naming for standard purpose classes (e.g. *Repository, *Service, *Request, *Controller, etc), so we also make sure a class doesn't contain that standard name in the wrong package, or a standard name doesn't reference the wrong layer. E.g. *Service shouldn't access *Controller. This can be especially beneficial if you don't further divide things up in a vertical slice.
i successfully use NsDepCop for that purpose in a mid size project ua-cam.com/video/rkU7Hx20Dc0/v-deo.html
Yes, I should of mentioned ArchUnit an similar, but totally forgot! Thanks for the comment.
That sounds very useful, I was worried about how to enforce the architecture and had never heard of packages that serve that purpose. Thanks for sharing!
There are always tradeoffs. The trouble with monolithic code patterns is that you often find similar usages across the vertical layers that require you either to couple one tower to another or else result in code being replicated across towers. I have seen the results of this pattern of not having a single idea of a product across business domains, and you end up with massive code replication and systems breaking routinely in production because one team subtly changed its definitions and business logic and this impacted other systems but was not caught in testing. The number of test cases that have to be written vastly increases and so forth.
In a real sense people are just pendulum swinging back and forth between different design patterns and as they get more familiar with one they start getting grass is greener on the other side issues, and start longing for patterns that were previously abandoned.
Whatever structure you go with, you still have to have a single representation of a determined concept in your code. In vertical slicing, what stops you to have kind of a "core" package that shared smilar code ?
You don't have to replicate the code; just extract it into another module and use that module everywhere it's used. And it should be sufficiently uncoupled with the modules using it to avoid future refactoring, just as its identical implementation in a layer would be. The only difference is now you're calling the layer in each module that needs it from within that module, rather than on all modules unconditionally.
nice new perspective in structuring...
the cake slices example and they way explained cohesion with it...
so beautiful.
it really makes sense.
wonderful
Great video, awesome points and I mostly agree with all Clean Arch presented concepts!
I do have a point to add though, the dependency direction/coupling of the project exemplified at 5:44 seems wrong (or confusing) to me according to the Clean Architecture book's concepts (unless the Infrastructure layer shown is an Adapter layer called Infrastructure and not the real Infra layer which would be coupled with a specific tech choice).
That is, in my understanding, WebUI (blue layer/external layer/frameworks) must not reference an "infrastructure" layer (which should be blue, not green, cause it's also an external layer... the green layer is an adapter to the infrastructure where you must invert the dependency direction (DI)). A "purist" (by concept) clean architecture in this example (IMHO) would go:
WebUI ->| Application -> | Domain
_________| Application (I)|
Derek, your videos are just so good. You take the time to describe things I've spent over a decade learning in such great detail!
Thanks! Appreciate the support. Glad you enjoy them. Just trying to distill my own experience/knowledge in a concise way.
This is great. Having all the in-depth argument for this approach in one place is priceless. Thank you!
Just realized that GraphQL is CQRS by design (query and mutation). And using Apollo Federation and extending shared types is a way of slicing a common schema model and allowing each business area to add their specific view about e.g. a "Product", which is a cohesive architecture pattern by design. The only way to mess up coupling at that point is shared libraries which may still add coupling between different business areas.
I didn't talk about it at all in this video, but coupling usually comes when "needing' data between boundaries.
😮 where has this video been all my life? I've just spun up another service using clean architecture in the classic form....thank goodness I've caught this early!
I do much agree with you, it's crazy. Thanks for all the context around every concept!
Excellent explanation of the concepts. Many of your points about the creation of turds I have seen created over time. The importance of the different contexts against the same data is critically important. Excellent video!
Such a convoluted solution for a non-problem.
The motivation for vertical slices is always having to dig through folders to get all the files for an entity/feature.
Whenever I find myself doing this in layered architectures, I just use my editor to search for the filenames that contain the entity name and then open those. Problem solved.
Not really. What is the size of your codebase? How many different domains are mixed there? Do you need to migrate some of them at a time, or everything applies to all of them at once?
It’s not actually a full vertical slice. In your example you are only slicing up the application layer but still leave other layers (i.e. infrastructure). Most examples I have seen also do this, but they don’t achieve what the commonly used image actually displays (slicing UI, application, domain and infrastructure).
Thus, you still end up with layered architecture in the end.
However, if you were to be consistent with the slice, that would mean plenty of code duplication, for instance, repositories would be sliced across features, and so forth, and that is not ideal.
"repositories would be sliced across features, and so forth, and that is not ideal"
Sometimes it's ideal, sometimes it's not. Sometimes features use different repository methods making it pointless to share. Sometimes repository methods try to do too much to serve the features that share it making it bloated and inefficient. One feature might need 2 pieces of order related data from one data source, another might need 50 across multiple data sources.
I always start by putting my repositories in the slices and then as the feature set grows I pull out what makes sense to share and leave the rest. If the shared resource gets bloated later on, I break it up to the slice level.
@@bike4aday I feel like there is a lot of exploratory work involved in Vertical slice architecture and we are still "getting to know it".
There are also mixed opinions and criteria of what should or shouldn't be the case with these. For example, if we dogmatically did it, with maximum feature isolation which does not leak out to other features, like in article "Out With the Onion, in with Vertical Slices", we also end up with *funny* things like css and FE code along with all other BE code.
You aren't going to have a DbContext per request. Nor would you have an aggregate per.. It would be for a feature set. The point isn't share nothing. It's putting related things as close together as possible.
I find the distinction easy to make.
Business processes/operations are self contained - they are the slice.
Loading data for a slice is part of that business process.
2 processes loading “the same” data is just coincidence. I won’t go too much into the pointlessness of using repositories with EF core ;)
“Infrastructure” is shared code. It has nothing to do with the business problem you are trying to solve. It is utility/convenience. e.g a “GitHubClient” which essentially wraps an “HttpClient” and exposes some specific methods to interact with GitHub/some 3rd party API
@@kabal911 It actually typically has a lot to do with the problem you are trying to solve, for example, Order entity is an infrastructure piece (DB/ORM). Same goes for Order router.
Probably rather than using infrastructure which confuses things it’s better to use “shared”
Separating by project/dll/package, is more about independant delivery/deployment and also team dependency, so it's better to separate by project/dll/package, trying to reason in terms of Dependency Inversion Principle (from SOLID) as suggested by Clean or Hexagonal Architecture. It's about seeing deliveries as PLUGINs for an independant package.
I think that a good way to think about coupling and cohesion may be the opposite as everyone does.
A single unit may have low cohesion (lot of responsibilities) but it has 0 coupling by definition because it cannot be coupled to itself. When you split that thing in two to make it more cohesive, now you got coupling.
That means that splitting things increases coupling and cohesion so they are opposite forces. It's an art to win in this situation and applying prescribed solutions doesn't help.
Also I see a lot of people that think that the mere act of splitting things reduces coupling when it's actually the opposite (e.g.: Microservices)
Yup, exactly. As mentioned it's a push/pull relationship.
@@CodeOpinion yes, nice video
This is brillant I wish I had the experience and knowledge you have :) thanks for the talk
Glad it was helpful!
Great video, great presentation. Something was screaming "bounded context" at the back of my head all the time, though.
Your "features" are a level of granularity lower, but the example of "product" meaning different things to different users is how I understand "bounded context". Two use cases may be talking about the same physical entity but each views and handles it in their context, using their vocabulary and their features.
Yes, macro is a logical boundary (bounded context), within that features are at a more granular level.
Been waiting for this one! Will enjoy listening in during lunch tomorrow :)
Hope it's everything you thought it would be! 😂
@@CodeOpinion was great! Though it raises a few questions.
If you do sliced architecture and need some background jobs like azure functions. How we do it is sharing libraries between the api and the function app to make sure both are deployed in case of underlaying changes. In those cases we actually end up with some middleground where we make a Core library that has shared data models and infrastructure to avoid having to duplicate models and forget to make changes.
I'm also interested to see how a VSA would look without MediatR. I guess you would end up building something similar?
When you put controllers in same file sliced out, how do you deal with shared routing eg. api/products... do you put that as static constants? Have you tried using minimal apis with this approach or the nuget FastEndpoints?
I'm also all for putting multiple classes in the same file. This is common when doing frontend do why cant we do it in backend? :) i have managed to change the mind of one in my team, so now we do it hehe
One of the biggest advantages of layer architecture is that you can control what you expose to the next layer and also prevent spaghetti code. With just vertical slice, it's really hard to enforce decoupling and when working with a large team of developers people are going to mess things up. One idea I have in mind is having a Clean/Layer architecture and each layer is a separate vertical, trying to merge the benefits of both ideas
Understanding of coupling sure helps. There are ways to enforce a direction of dependencies beyond physical projects.
I had the same experience. Working with folder structures and in a pragmatic way was extremely difficult with large teams or teams with not enought seniority. In the end you need silver bullets for everything. Many projects to avoid coupling at compile time , mediatR to avoid fat controllers, even microservices just for damage control the devs etc etc.
Having said that... great video @CodeOpinion , love your work.
Not wanting to take away from what has been shared because it's awesome, as ever. As the video identifies, there is some value in cohesion along horizontals too. The domain is an obvious one, but the API can benefit too: HATEOAS is a love letter to cohesion across the top of the stack.
That was like a lesson in the university, thanks!
What about same application code being used by API, or gRPC or WPF forms should we put all of those “presentation” classes together? I mostly agree except with having the controller class bundled together.
This would exactly be the reason to have those in separate projects. Projects/assemblies are exactly for this purpose, reuse. So ya, don't put frontend with the rest of it.
I think this might be your best video yet. It provides a lot of context to how you think about architecture that isn't always clear in the shorter videos. I think a lot of those will make even more sense if I re-watch them after having watched this one. This is way more than just a video about project re-organization. It's about a better way of tackling problems (features) such that you use the best code for the job. Don't create a domain layer for a simple feature that only needs crud. Doing so will be the equivalent of wearing snowshoes in summer. You can still get around, but it's going to be longer and more complicated than without them. Likewise, using CRUD for a feature with complex business rules is like walking through deep snow in just your sneakers. You're going to fall down a lot.
Anyway, great job. Super helpful!
Ya, this video is really a combination of a bunch of videos that I've already done. Just makes the whole concept in a more cohesive (pun-intended) video.
1) This argument is somewhat similar to Uncle Bob's one, "screaming architecture", discussed in its book "Clean Architecture"
2) Using different projects in .NET enforces the acyclic dependencies principle, i.e., you cannot create circular dependencies. Without this division, you have to use tools like NetArchTest to have the same feature
3) For Web APIs, it is possible to use the REPR pattern (e.g. in .NET, Ardalis ApiEndpoints or FastEndpoints NuGet packages) to favor a cohesive structure of the files
4) The example of a product, discussed in the Informational and functional cohesion section, has been covered in detail in Mauro Servienti's talk "All our aggregates are wrong"
Thank you very much for your clear and thorough explanation! I prefer this longer format.
p.s. I'd really like to see a video with a list of recommended books!
*2) Using different projects in .NET enforces the acyclic dependencies principle, i.e., you cannot create circular dependencies. Without this division, you have to use tools like NetArchTest to have the same feature*
I've inherited a few projects over the years where this is most definitely not the case.
Awesome examples to really pin down the argument. Great job.
For anyone in the Node world and don't know NestJS, it has a wonderful ability to slice the onion so that you can build modules of feature functionality, which are like mini-onions. Very powerful!!!
The whole onion architecture is basically intended in the Node backend world with the request context being passed through a series of middleware functions. It's trivial to keep the style going from the middleware to the actual endpoint functions if you use typescript decorators, since they're just functions that wrap the function they annotate and are executed in the same order they're written. So you can have @Authorize @Validate @Whatever endpointFunction() { ... }, and it'll run authorization, then validation, then whatever and then the function.
Thanks, Derek, very interesting video. I have a question, though. What happens when you have multiple clients that have the same feature but that show different data? For example, you could have a SPA, an MVC app and a mobile app that all need to display different item data. How do you do this? Typically I see people returning the full data with all the fields for each one, but if you only wanted to return the necessary data for each how would you achieve that? Would you add query parameters to the endpoint that specify which fields you need? But what happens if one of these clients need the items to be joined with another table/entity for additional data? I haven't yet found a good solution for this.
You're getting into BFF (Backend for Frontend) concepts with this and view/ui composition. I haven't done one exactly on this, but have talked a bit about it in here: ua-cam.com/video/ILbjKR1FXoc/v-deo.html
I don’t see how this is really different to “traditional” architecture. You would still need separate/different endpoints if your REALLY wanted to support different data shapes.
The problem is not the code organization, but the endpoints/REST. This is ultimately what something like graphql tries to solve.
You might want to look at odata
Can you share a link to the GitHub Clean Architecture repo in the video
Absolutely great and helpful video! Thank you, Derek!
Glad it was helpful!
Amazing video and concise examples, nice work! This is a common topic and all because IDEs don't allow the creation of tags and scopes for project structure visualization. I'm currently working on an extension that allows you to create your own project layout views using annotations. Then arrange your code and files as u want ;)😉
If you're optimizing for number of files opened by the developer you can always put your entire code in one file :P
ha. I've heard of people actually doing this. Don't recommend. I do recommend as I mentioned when files length still relatively small.
Very detailed and good explanation about Vertical Slice Architecture. Thank you!
Excellent explanation of concepts. Thank you for making this video.
Glad it was helpful!
Awesome video, thanks. I wish this design was more broadly used, in projects with frameworks like Rails it's really hard to see it in use
I wrote a Blazor app for work a few years ago and followed the Clean Architecture structure. I've been on the hunt for a good way of structuring apps for years, and I tried it out for this app. As I was developing it, it kinda made sense. Then I deployed the app and went away for a while, doing other work. Then I had some change requests and bug fixes for the app. And looking at it now, it is a complete mess! Exactly as you describe here - files in so many different places across several projects, so making a simple change can involve changing ten different files.
At some point, I'm definitely going to rebuild the app and base it on a much simpler structure. VSA might well work for that. It'll certainly be a lot better than what I have now!
Yes yes and yes. Started my first job as a junior feeling ready to make some nice layered code with nice abstractions and it looked awesome when i was done with the initial codebase, only to absolutely hate whenever people asked for new features / changes, because i had lost the overview. I was afraid of changing stuff as the use cases changed
Lately i've been grouping stuff based on ownership even if that called for some duplicate code here and there, but it guaranteed me i knew what would be affected whenever i went in to make changes.
when using a single database, is it worth splitting the domain into smaller ones for each function, or is it worth using one super-domain project with a description of all entities? for example, if there are about two hundred related tables, when updating one of them, there will be a lot of work when updating its entity locally for each function. What is the best thing to do?
Excellent video. Very well explained. Thanks.
With a legacy solution, a layered monolith, how would the vertical slices be introduced into the same monolithic solution without fitting it into existing (non-clean) layers? Maybe a new project? Then vertical slices within that same project? Or a separate project or set of projects from each slice?
Excellent, really apreciate u time. Very useful.
I love the way you say "I'm not that way" .. its kind of implying that people with "those" beliefs are somehow misguided, but you're not making a value judgement out of politeness/repect
This is all fine and dandy, and you make some good points, points I wish more 'legacy' companies would consider when hiring people who actually WANT to make the systems architecture cleaner.
Unfortunately, the reality is many legacy companies (perhaps not the kind your example shows) operate on a "let's put all our business logic in the database, but never document it or track changes" mentality. This completely nullifies and obliterates any sensible architectural concerns (not saying MVC is good architecture, quite the opposite, but at least it can be refactored and tracked by subversion).
TLDR: Document your SQL in some way, or resign as a developer. I'm tired of having to guess what your complicated storedproc does because you spew a bunch of CAST()s and SUBSTING() without actually naming your variables (especially table aliases) something sensible and self-documenting.
There's also the "SQL is the way, the truth and the life" mentality, which is retarded.... there ARE other dbs out there and not all of them are trendy toys like MongoDB (Cassandra, Redis, and Neo4j are all exceptional at their jobs, yet I keep landing contracts with everything being stuffed into SQL Server like it's the 1970's)
Grouping classes (that belong to one layer) in a single package, module or project has always been counter-intuitive for me. Just because a class has the "Controller" or the "Activity" in its name (as a suffix usually) doesn't mean you have to put all the controllers in the same holder (i.e. folder), as these classes have very little or nothing in common.
Instead, breaking down the application into the features (rather than layers) and then designing every feature as a single component/service, which contains many cohesive sub-components/classes, is a much more flexible architecture, if you later decide to, let's say, extract one feature as a micro-service or simply replace the libraries for event handling, messaging or even introduce a new DB. I am very happy this video recommends/approves this very same approach,.
One more thing, working on my bachelor thesis (ages ago...), named "The Cohesion in OOP", helped me to question the "layered" approach from the very beginning even though I had a very limited experience in software/code design, so I think it is very important to cover (or at least get familiar with) the theoretical aspects of the software engineering. It certainly helps (from my experience) to recognize and avoid the scenarios that could give you troubles in the future.
Great video with a lot of detail. But, one file having the whole slice/feature in with potentially 100s or 1000s of line long sound terrible, most likely would have regions all over it. One reason why layered/clean architecture is so popular is everyone knows it and understands it, when working with external developers this is beneficial as its something everyone can relate to.
Generally, these files don't end up large at all. In my experience, around 200 lines give or take. And no, you don't need regions 😂
Introducing and selling vertical slicing is not too hard in my experience. Developers get it instantly, including external developers and fresh from college juniors. The benefit of not having any significant merge conflicts when working in parallel (feature/developer) is a big selling point. Other architects are harder to convince, like always.
Thank you. The content of your video is very practical and pragmatic.
Glad you think so!
Great video! How do you feel about VSA on the frontend? I'm currently researching how to scale large frontend applications using design patterns, but a lot of resources only talk about the backend.
I’ve followed vertical slice architecture on a very large project (with the nested class for naming) - one thing we don’t do is the controller per feature which is an interesting idea. We have a partial controller for each entity, with a another partial for the actual feature route. I think I like your way. Not sure what impact it would be moving from 10 controllers with around 500 actions, to 500 controllers?
Good question. If anything, startup time of it discovering all the controllers. But how impactful that would be, unsure. You'd have to benchmark it.
At 8:11 would be really helpful for random access viewers to label bottom as “business domain” … one of these is not like the other. (If that’s the case, not an msft person)
Longer length of video is great. Liked it Derek.
Thanks I'll try to throw a longer video up here and there. This really is a bunch of my previous videos over the last couple years mashed into one.
You said that we got rid completly of layers ,but what happened with the domain model and infra layers?Thank you!
At first specifications looks nice but then you realize they are a very limited overhead over a dbContext that is already an abstraction of the database. I loved how you grouped your features and files with multiple classes per file.
Do I have to implement Command & Query, Event Sourcing etc. to be able to make use of this vertical structure?
No. Absolutely not.
thank you for this explanation, but I had some thoughts in my mind regarding this
as I know clean architecture is not just meant for cohesion but also meant for isolation between business logic and infrastructure, in clean architecture you need to build some sort of abstraction layer using facades and adapters to avoid technology changes, so for example if you wanted to change the database, you can build the actual implementation that matches the adapter layer and here you go you changed your infrastructure without affecting other important areas, but in vertical slice architecture, while you are grouping related things together, if you wanted to change your db to another one, how much change should be done?
I have to say thats a fine piece of cohesive cake.
The only thing that overthinking architecture ever did for anyone is get solutions stuck in a dependency catch-22
What software architecture has taught me over the past 20 years is that software architects are addicted to solving non-problems.
In compiled DLL languages these problems that we are trying to solve are basically build into the DLL model itself. Basically projects: the architect’s favorite folder.
Completely made up doctrines like no upstream dependencies are primarily due to how compiled languages have separate DLLs requiring each over instead of just compiling the gdámn executables from the various dependencies.
The no-circular referencing of BLs is an OOP problem, to which the solution was always staring us in the face: less architecture, not more. Functions, not BLs.
The BL itself is a failure to do the basics right in the first place. KISS and separation of concerns.
The BL is itself an encapsulation of concerns, but a function isn’t. A function can have a dependency on another function that has a dependency right back on itself, and it’s fine. We even gave it a fancy word.
These same original DLL and BL problems just keep getting more and more fancy ways of solving the same self inflicted problems of too much architecture and not getting the basics right.
What do we do when one rigid BL needs to call another rigid BL that itself depends on that other one? We pull that functionality out unto a less rigid “helper”. And those helpers are just functions. See what we did there?
Now just take that same idea to the limit and get rid of the rest of the artificial, self-inflicted rigidity, and all of these fárt-sniffing solutions to the same old problems we created for ourselves go away, by OBEYing the fundamentals of software architecture.
1) KISS
2) SoC
Do these two things and vertical slices becomes an eldritch solution to a problem that no longer exists.
Then compile your in-house code to a (A) dll, and your upstream/downstream solutions become a “wtf are you talking about? What is upstream mean?”
It means that architects treat projects like folders, but to be fair, these problems are baked into the project based OOP programming models themselves.
Yes!!! nothing wrong with multiple classes in a file, had discussions on it... i like my interface right above my class in the same file. If i have 2 implementations of an IStorageService, one for local file storage and the other for writing an reading from a blobstorage, i like them in the same file. So glad i am not alone on this.
I disagree with this one. 🤷🏻♂️
@@rowser4472 without a sound argument against having an interface close (in the file) to the class that implements it is has no ground.
@@rowser4472 Why?
This has been a consistent approach I have utilized for more than 15 years. I probably should have coined it sooner. Thx for the video.
So what’s the point in using MediatR in this example, rather than putting the logic in the controllers?
Your controllers should handle only the HTTP request-response cycle. Such as receiving inputs, calling services and return responses like succes or error messages. Your logic should be handled through a Service layer which get called in your controller. This is done for many reasons:
- Reusable: for example a UserService.EditUser(..) function can be called inside the ProfileController for users and inside AdminController for admins.
- Maintainability: If changes happen you only change the Service function and both controller endpoints will work right out of the gate.
- Testability: simulating HTTP requests to hit your controller endpoints during testing is annoying and difficult. It is much better to instantiate the service class, execute the function and then test it.
- Scalability: as your app grows you won’t lead to code inertia where it’s difficult to change or add new features. This separation will keep you to ship rapidly. MediatR is excellent for keeping controller functions at max 3 - 4 lines of code and transfer all your business logic to separate Service layers
One of the best, I would not say video but guide, arround Internet about SW Architecture. You touched some wounds over here (like, c'mon.... have you ever read the name of the channel?).
Thanks. It's all intended as food for thought.
Can you make a video? Over migration from relational to no sql. Taking reference of schema you shown at 23:00. What need to taken care. When need to embed, when we should go for relationship etc. I would love hear those key points.
Interesting suggestion!
Thank's for this Derek. Is there a template such as the one for Clean Architecture for this approach? It's always much easier to start doing stuff in a different way when there's an example how this is done. If the template gains popularity people will most probably be willing to contribute to keep it up to date.
I plan on creating another video that better illustrates some of the structure. Won't likely be a template but should get more of the gist across.
22:20 i would prefer not to put everything in one file and rather make separate files in the same folder
why? because i dont like scrolling, and when i open a file i wanna see the thing it does.
i also place shorter functions/methods higher than the longer ones so i can see many thing without scrolling so much.
and time to time i open stuff next to next on the IDE and its not possible or hard if they are in the same file.
i also dont like nesting stuff into multiple folders deep, but i would just put everything into their own file in the same folder
Great stuff - thank you!
@CodeOpinion may I suggest this is very much the idea (loosely) of how Unix handles things via scripting together a bunch of relatively simple utilities: not all of them have I/O other than standard I/O and stderr, nor do they need to: they may instead set the system to a particular state instead as they have data filtered through them, or any other arbitrary number of things.
It’s true, it’s not a perfect analogy. When building up complex systems of scripted components like this in processing pipelines, it’s easiest to do it incrementally along the way. Ultimately an “application” is just a bunch of simpler processes chained via the script. I’ve for many years considered this is likely a better way to do things within a single process instead of the Unix method (or using PowerShell, which is more OO) of composition by smaller programs.
I’d suggest a great advantage of doing things with these smaller vertical slices however it is done, is it isn’t as painful to obliterate something you wish to remove or replace, in all aspects: all code is easier to delete, and code that is easier to delete is easier to perfect, where the ultimate perfection is no code at all: that’s one bit of code you can be sure won’t be buggy 😉
Wonderful video!
I love it.
I have a question. If I share a model between features, I share property and behaviour that don't interest all the feature.
Is there a way to solve it?
Example a shared basic model only with SKU property and treats with property and method, in this way I can share logic, I can build custom model for each feature.
The same for repo. I don't delete method available on update feature.
(I understand tha I can execute a simple query instead a orm function.)
Is this a good way in your opinion?
You don't have to have a "model" that's shared at all if you want to simply use a transaction script. I only suggest it if you don't have consistency concerns and it's really just a data model. At that point your transaction scripts are implementing the behavior. If you do have a lot of logic, complexity, and need consistency, then stick to an aggregate. Check out: ua-cam.com/video/aLFMJ_frafg/v-deo.html
Loved this video, I think this is a really underrated topic.
I'm not sure I agree with the framing that increasing cohesion increases coupling and vice versa. Take the reddit guy's data model as an example. If you were to stick whatever that app is into a typical layered structure but without some kind of vertical/feature slicing, you would end up with a ton of coupling caused by the center of the layers having very little separation of concerns. All the features would be extremely brittle to change in one another. This feels like coupling to me.
I think maybe a more accurate framing is that high cohesion creates greater local coupling in exchange for the benefit of lower project-wide coupling. The intra-feature bits that do cohere with one another will be slightly more coupled - which costs much less because of their natural relatedness - but the rest of the project becomes significantly less coupled to each individual feature, which is a far more expensive kind of coupling.
Curious what you think about that.
Well said. I'd agree with that.
Very nice video with a clean explanation, I like it. However, one thing still bothers me; why did you put the controller into the vertical slice? Shouldn't it be at the edge, like persistence? Or another way around, shouldn't you also put the persistence into the same vertical slice?
Persistence was shared several requests, hence why it was directly in the same file. The controller with the single route was in the same file because it's specific for that request.
Do you have this code sample on git?
No. There really isn't much to it. I just moved files around for the most part from the original eShopOnWeb.
Whats the difference between coupling and cohesion?
Glad you asked, check out this video. ua-cam.com/video/YDNR_gfBk0Q/v-deo.html
Interesting one. Do you think, we should have seperate projects for logical concerns, rather than projects split into clean structure like adding domain, application etc? Could these be folders in a single project, for vertical slice?
You can, but you don't have to. Projects are often just use as a physical barriers or to prevent circular referencing. You don't need multiple projects at all. You can just use a folder structure within a single project. All depends on what your needs are.
I couldn't agree more with this. This is common in other stacks; Django and NestJS are doing something similar to this automatically.
How do you do domain validation in a reusable way within this architecture? This would be outside of your normal validation making sure this is a valid email. Something along the lines of ensuring the email is unique or more complex scenarios where you have to do a DB call to validate this is a valid action given the persisted settings.
What is the reasoning behind having just one controller per feature?
Any changes to your feature, are isolated to this one controller. In other words the controller class will have only one reason for change.
How do you organize UI code, which often spans features?
If the UI is within the same platform, then next to it. For exmaple, if you're talking about MVC, all of them can be organized in code together. If you had a iOS app and a .NET Backend, that code won't live together from a development view, but it it is from a logical view.
Excellent video Derek! I still have lots of question regarding Vertical Slices, but I'm getting to it...
What's your opinion regarding that issue:
Let's say I have a use case that involves 4 changes to the database on 4 different Services, one depending on the other to get the ID for example. These changes are within methods and they call other repository methods. How can I mitigate issues if something fails between one update and another? Rollback is not an option since I am working with different Contexts.
Workflow. I have a bunch of videos on this, but first top of mind: ua-cam.com/video/hGiPWfWG8gs/v-deo.html
Very interesting lecture!
Glad you think so!
Great Video, Thanks!
C# slowly moving towards idiomatic Rust practices ;)
Can you provide a link to some github repository showing this approach (vertical slices with e.g. clean architecture)?
I'll be covering it in a video sooner rather than later that has a more concrete example.
So vertical slices is about expressing the "virtual" vertical slices across a layered architecture.
My problem is that even you go great lengths to create vertical slice at some point the slices will share functionality with other slices. Excellent example is authentication and authorization, the functionality is the same for all slices. If you plug it into all or most slices it becomes a layer. At the end you do not want to directly depend on the data persistence solution, so you will build an interface and implement a service.
Slices without interacting with the domain are the definition of services?
Thank you Derek
Great video, it's a great structure for larger projects. I'm having one issue though, and I can't find where in my configuration I'm doing this wrong - When Nesting the items under a static class (22min in), it all works EXCEPT for the controller. As soon as I put the controller inside the static class, it fails to find and expose it.
Any tips on making this work?
Why is your controller nested inside a static class? It can be in the same file, it doesn't need to be wrapped in a class.
Always great. But I have a non related question, my work experience is 10+ years. Now I want to become an architect. What will be starting point and path for me? Please suggest. Thank you!
Here's some advice I'd give to my younger self: ua-cam.com/video/pSMXDfRfyEc/v-deo.html
Good points. But if these layers aren't physical separated, you will have people start directly referencing infrastructure code in your UI code. Then we're back to the 90's. There's nothing wrong with that, if your app is small.
That ☯️ thing explains it all. It's a balance and it depends.
Thank you!
Welcome!
Hey Derek
Thank you for the great content, i was messing around vertical slice arch for a while now and i really enjoying it. But there a question, if the controller and command and command handler are basically in the same file why do we need mediator then?
You don’t… see minimal APIs
Something like MediatR separates ASP.NET Core from your application code. You're converting an HTTP request into an application request. You don't need MediatR to do this, but it forces the concept. However, if you were to put HttpContext or anything ASP.NET Core into your requests, you're losing some of the purpose. I find the true benefit if you're creating a request pipeline for your application (mediatr) request. There are other libraries that do this beyond mediator that also work out of process (wolverine, brighter, etc).
Most of the time you don't, especially for small services its not required.
My Tech Lead recommended me this channel and gotta say you immediately earned a new sub🦾 Great video really. I have read about similar dicussion about Cohesion and Coupling from the Modern Software Engineering Book and I got to say spot on your thought process!
Thanks! and Thank your lead for the share!
Multiple classes in the same file is code smell to me, even if IDE's allow you to find it. It makes it harder to modify than necessary when you don't have it collapsed when scrolling around... Especially if they have similar looking code. There's a reason why classes are per file. I agree with DDD though and organizing by logical/feature-based layers. Microservice architectures basically lend themselves to this design strategy.
I would like to know your opinion on how you would deal with the following scenario. Let's say we have an API project where we implemented features using Vertical Slice Architecture. All these features(slices) are implemented in the Features folder using the illustrated pattern from the video. Now we decided to have Blazor Webassembly as our frontend and we would like to reuse requests and responses(commands/queries) from the API project. What would be the most appropriate way to share these requests and responses? Would it be okay to create a DLL library(contracts) that would mirror our Features folder from the API project and declare there only requests and responses(commands/queries) and then we would reference this DLL from both API and Blazor projects? With this approach, it would be theoretically enough then to implement those queries/commands in the API project and we should be able to reuse the same code between the frontend and backend. Or is there any better approach for this kind of code sharing? Thank you
Yes, do that. Third project with the models you need shared.
Thanks for the video! Can you make practical video about project with this type of architecture?
I should, good suggestion. It will probably be more about naming and code organization than anything to illustrate.
Thanks man