If you've watched any of my other videos, you know I'm an advocate for vertical slices and focusing on features and organizing code that way. I didn't really mention them in this video directly but I plan on creating a video dedicated to it.
I have done away with terms like "Clean Architecture", "Ports and Adapters" or "Hexagonal Architecture" and just call it by its family name: "Inverted Architecture" In the end, it is just a manifestation of Inversion of Control.
I would love to check the document of your essay if it's okay with you. Your reply to my separate comment about CA+vertical slices was held from being published so I only got a preview of it from my notifications, probably because it contained a link to the essay. Maybe having only the last part of the URL would circumvent the issue? A shame I couldn't read the rest of it
@@lunify2814 indeed...it seems that youtube has some strange policies, when it comes to sharing information. I merely included my name on the platform with the little blue bird and a request to contact me there directly ...the name is "beamologist". Hope this reaches you....if not, I'll have to make a video :)
There are some important differences between the different architectural approaches with IoC. Bob Martin discusses them in the last chapter of the Clean Architecture book.
@@rothbardfreedom Of course he would say that, otherwise there would be no book to sell. A wise man once said: "If you can put a label on it, someone in the marketing department is smiling"
I find that if you don't setup the appropriate layers first, you never do. I've come to distrust any talk of "this app will only do X" because they always grow and become monsters (without a clean architecture). By the time you realize the problem, you end up contemplating rewriting the app from scratch. Thanks for the video. Love this channel.
Totally agree with this! I'm a Solutions Architect and I constantly bang my head against a wall arguing with developers about why they dont need CQRS and DDD in a CRUD microservice. We double or even triple our development time (and testing) times because of it. We have a huge number of services and the majority of them are really simple REST API's with simple CRUD behaviour. But you open up the code and its layer after layer of abstraction for what is essentially a controller and some CRUD. Development times stretch out and individual microservices becoming overly complex for absolutely no reason other than to stick to the gold rules of "Clean Architecture". It drives me mad. Use the patterns and processes when they're relevant; not just because you've seen a video somewhere telling you its the best way to do everything..
The more one digs down into the subject of distributed systems, the more one discovers an intrinsic incompatibility with Active Record style state management, in favor of immutability (Event Sourcing/CQRS). It doesn't really matter if or how many well-crafted defensive asynchronous patterns are implemented, in the end, one cannot stop time and in CRUD based "microservices", implying multiple sources of truth, there is always the risk that a source of truth is no longer relevant in relation to the messages in the queues (which are yet another source of truth). Given the CAP theorem, this means that if one service fails, the wise thing to do would be to bring the whole system down (and thus virtually "stopping time"). Does this make sense?
Sometimes, it's beyond cohesion. When your software is large enough, even smaller pieces that don't need a business layer should have a "dummy" one just to have a consistent approach accross the entire code base. Sometimes, when you work on a first subsystem that is built in a certain way and then you go to work on another one within the same software that is built differently might be confusing. So sometimes it is good to have everything layed out the same so developers won't need to think about how this piece is made each time they need to work on something.
I do understand what you're getting at with being consistent in your codebase, but I do think we should give developers the benefit of the doubt and assume they can understand context. I do understand what you're getting at though, I just think we should expect more from developers not to just be cogs in a wheel and "feature machines".
More context matters. On large scale company where the turnover are high, with clean architecture people can make changes without understanding the whole system, so it's easier to get up and running. I think this is the main reason why it's so popular (also to deal with Product Manager who keeps changing requirements all the time)
Good vid! There is a nice middle ground between classical mess and clean architecture that people kinda forget about: Hexagonal architecture or ports/adapaters. You have a core project which kinda is like a combination of Domain and Application. You define all interfaces in the core: primary ports for services that want to use your core and secondary ports for the core to use external stuff. So for example you define an ICarRepository as a secondary port and have the implementation in the Persistence layer. The CarRepository implements the ICarRepository defined in core, but is an internal class. Via these ports you can attach any number external systems to the core. As long as all interfaces are defined in the core and all implementations are internal you can ensure that the core has no outward dependencies. If you want to lets say refactor from using Oracle to Dapper with MSSQL as your data access you just need to implement the same interfaces and can attach via the same port.
For smaller apps I tend to just take a traditional layered approach which makes any business specific code easier to separate, if any as the app grows.
I think you hit the nail on the head. I love Clean Architecture, but I do think that it's popularity and subsequent misuse and over-application is a consequence of "blog driven development" If someone really wants to understand Uncle Bob's "Clean Architecture", they need to just read his book and note a few of his Caveats: 1. It's an paradigm, not a recipe 2. There could be more layers or there could be fewer layers 3. Its not a packaging paradigm (but he details what you refer to as "horizontal" and "verticle" slices) 4. I'm pretty sure he even suggests that, as a paradigm, it's not practical for trivial projects You brought up a *really* great point about separating the database layer from the entities layer. I think TODO lists are wholly impractical for anything but a beginners guide to MVC architecture; they simply fail to acknowledge the treacherous nature of entity relationships with respect to the separation of database layer and the entities layer. I think your point about commingling the database layer and the entities layer for trivial applications needs to be taken to heart. I deeply appreciate that you referred to entities that bring nothing to the table as "pretendo entities" or whatever you called them #useless 😂 Great video.
In my experience, the benefits of implementing a standard for solution organizing (like this one) outweigh the cons. Having basic decisions out of the way (layers, naming, references) removes a lot of hand wringing and pontificating that happens at the beginning of a project and keeps people from reinventing the wheel over and over. Personally, I can’t stand moving from solution to solution and seeing inconsistencies. Clean architecture might be a little prescriptive. And naming and layering consistency across a portfolio of projects might be good enough for many.
Exactly. It's why I promote it too, as we are a small team with turnover every couple of years. And frankly, we all need to be able to take over a project instantly when someone is ill, or whatever... Ok, this addresses a structural problem of resources, but so be it. But that is part of "context" too. Although I always say to everyone, if your project is small, and CRUD, then don't mind. But once it has any form of business logic (and some CRUD already has that - without you realising it sometimes), then split it up please, so we can build upon it and don't need to refactor the whole code base as a small team.
Context matters! Knowing when to apply Clean Architecture matters. A lot of supporting applications end up just dealing with single concern where you should never even consider it and where such technical layering is only gonna cause more overhead. Having cohesive set of business functionality is usually enough. I only apply Clean Archetecture patterns in business critical applications which are much larger. Having separate domain/aggregates which are not concerned by any tehcnical infrastructure is the only way to properly unit test core of the system. A lot of times I see large systems where business logic is tested through large and slow integration tests because the technical parts are not properly separated. This is where proper layering and direction of dependencies matter.
This hard separation via projects always makes me think of the explicit file ordering in fsharp. You can only depend on something that comes before it. This helps you think about what you are doing and makes looking for the important/independent code simple, since it's all at the top. It also prevents you from accidentally doing the wrong thing like coupling your domain objects to implementation details like http/database stuff as that will result in compiler errors. Presentation/implementation should be underneath/depend on the logic, not the other way around. Using projects for this separation feels like such a heavy solution. At my job it's just what you describe: big projects divided in presentation/infra/app/domain, with countless of repositories and usecases. Most of it for what is just CRUD. Though I'm that familiair with vertical slices, this seems more like what we would actually want to keep things maintainable. Big fat chance introducing this though, since these layers are kind of holy around these parts :')
To me, this doesn't need a name, it's just good programming. That anybody would code something from the inside layers outwards just blows my mind. I mean, sure, maybe beginners do, but I would expect someone working in the field to have been taught this from the very beginning.
Think about the situation in that by 30 minutes crash course about CA lector gonna implement entire finical management system instead of to-do Obviously everyone should took pattern and solutions based on need and problem they are facing as always it's depend By over ten years experience as software engineer I'm gonna give you some advice 1-never do over engineering 2-chose solutions and patterns wisely 3-if your boss told you Go with CA, microservice ,eventsourcing or vise versa , accept that and don't argue
I find when working with microservices that each service is so small that this really isn't needed. They aren't using crud, they just usually only deal with a small number of types of request, often only a single RPC endpoint or brokered event. If I had to split a service into 4 projects, I'd probably say it means it's doing too much. You still need to know about dependencies, coupling, etc, but it's at the level of the services rather than the classes.
Doesn't CA coexist with vertical slices ensuring high cohesion while maintaining a clear dependency direction? From what I understood from uncle bob explaining CA, its sole purpose is dependency direction, while his screaming architecture is used in tandem, basically applying vertical slicing with entities as the base. I would love to hear your thoughts
Which framework? Like top web framework? database framework? It's not about if you're going to change it really, it's about how coupled are you to it. If you aren't and you need to change it, then doing so is relatively cheap in terms of time.
If a project or feature isn't large enough to have its own "sections" for each layer, we just stick them all in the same package. E.g. if the comment feature is small enough, all classes just go in com.whatever.comment. You can tell which layer things belong to largely by class name. If it grows too large we split things out into their own sub-packages, but I find oftentimes we don't need to. We also only follow a "clean-ish" architecture. In particular, we let the App layer have a more direct connection to the database. This is because of transactions and data consistency though. I've had some bad experiences and subtle bugs in the past when trying to abstract away transactions. Everything else is pretty straight-line clean architecture though.
Great video! I'm a junior dev and a big architecture lover. Usally i just put an abstract between my service layer and database layer, organize my code by what goes together and what is the responsibility of each of my components( class, function, etc)
Honestly I agree with everything but I strongly encourage people to build MVVM when starting new project. Even if it's really simple project without any business. It's way more scalable and the practice has proved that people do not make simple ToDo apps anymore. And it's always good idea to have the base project done well to make easier to scale in future.
"I had to open up so many files to make a simple change" is not a meaningful complaint. The question is how difficult was it to make the change, how likely were you to break something else while making the change etc. If each file you opened it was straightforward and clear what change you need to make and you were able to make that change cleanly and easily in a safe and well-tested way that was unlikely to break anything else, then you've had the best possible experience regardless of how many files you've opened. The biggest problem I have with n-layer architecture is not when there are too many files, but when there are far too few. I.e. when there are basically three massive files, one for controllers, one for "services" (business logic) and one for "repository" rather than splitting them up further by use case. I have no problem with layers, but I also want vertical slices. You can do both! I would recommend splitting up by vertical use case, but even then I still recommend separating out by technical concern as well: dice it up both horizontal and vertical. The primary reason is that if you don't split it up both horizontally and vertically, you'll get an idiot junior who thinks they are super smart l33t coder and they've found a fantastic way to be "DRY" and "eliminate code duplication" by introducing a bunch of horrendous spaghetti coupling between different technical layers. Ensuring you're not allowed to cross between layers of abstraction in one file eliminates opportunities for idiot 20-something programmers to try to be clever. "I had to open up so many files to make a simple change" is usually the kind of thing you hear from 20-somethings as they begin to realizing that enterprise programming is actually very boring when it's going well. They got excited about programming because they actually find it exciting to spot all of the shortcuts and optimizations you can achieve by jumping between levels of abstraction etc. They get excited about generic code, etc. You don't want that attitude anywhere near your codebase, when you are in your 30's you are happy to write mind-numbingly boring code and get your excitement after 5pm when you've gone home for the day early because everything is rock solid and working.
One note, I often think the "I had to open so many files" is because there's a lot of indirection, often times without value. Some folks really love layers of abstraction.
Slightly out out topic question. Lets say there is a modular monolith. Modules here are well defined and having good boundaries. If one module has to trigger a state change in other module , it calls the interfaces exposed by the other module (COMMAND) Let's say one module wants to lookup/query data of another module, should there be separate interfaces exposed by the other module (QUERY). Should the other module prevent its internal, models from being exposed (public)? In a microservice setup, (assuming each module becomes one service), they probably expose HTTP APIs to lookup/query data. Wondering how that can be designed in modular monolith where everything runs under same process? Cheers!
If you're crossing a boundary because you're doing view/ui/query composition, then expose some type of interface/delegate that's a contract. However, if you're doing some query to another boundary because you need that data to perform a write/command, I'd be curious if the data should live where it's required for that write/command.
@@CodeOpinion Lets say module A managers Users.. Module B has some Orders. Most likely Orders would have the userId to refer to the user. Let us say there is an ask to generate a "View/Projection" for Orders along with showing User Details like (Name , email id), in that case Module B probably has to fetch the user details from Module B. Module would use the userIds that it has in its schema to fetch probably? There is no write activity. Just querying to generate reports. Also, querying data from one module to perform a write in that module is a "Design Smell" for sure. :)
So safe to say in modular monoliths, for "reads/queries" , a module MUST expose contracts/interfaces for other modules to interact, even if it might be so tempting to access repository of other module directly
Amazing video with a clear explanation! How would you recommend a Junior to start learning DDD and clean architecture? I have added DDD because I see it in most places that describes clean architecture
Clean Architecture has nothing to do with DDD in my view. You can "do DDD" with CA or Vertical Slices or whatever. If we're talking about domain modeling, UL, boundaries, that has nothing to do with CA.
Most "piles of turds" start out as small apps where people say "we don't need to be concerned about architecture because it's a small app". Then that small app grows and things are added to a system that lacks extensibility. Comparing any business application to a TODO app is apples to oranges. Of course, if your app is never expected to change, you don't need to consider that; and something that small can be rewritten within a couple of weeks. Business applications, if they're successful, do grow. Considering that (like anything else) ahead of time saves you time later. PPPPPP
Then those teams fails to see when complexity outgrows their solution and don't apply refactoring and dealing with tech debt as a part of each sprint. It's no point introducing a big complex architecture if all you have is one database table to begin with. That's something you introduce when you actually need it. As long as you code against interfaces and follow SRP together with a high test coverage you are free to make changes at any time.
@@PelFox I agree. I didn't suggest introducing an architecture that doesn't make sense for a particular application. Just that there's a difference between not thinking about architecture (as one could do with a simple static app) and putting some thought into it up front - which some write off as unnecessary because of lack of foresight. After all, by definition architecture is hard to change later.
The issue I have with most decisions I disagree with is that they almost always seem to be made because someone heard it was a good idea at some point, without understanding the problems it solves. It might be the correct decision, but it's an uninformed one.
Business: Oh we just need a ToDo app. Later: Oh we now need the ToDo app to access a database. Much Later: So we need the ToDo app to be available to thousands of users and still needs to be performant. Sometimes, just doing clean architecture from the start is wise. Especially if it has the potential to change.
The counter point is, in my experience, that has never been the case. No up front design or exploration/understanding could lead you to this. As I mentioned in the video, defining boundaries is absolutely #1 thing to get done. If complexity creeps up, it shouldn't be within a monstrosity of fat wide layers but in a specific boundary. In order to define boundaries you need to better understand the domain.
There is nothing stopping you doing "CA" in a single project, or even file. The concept of invertion of control still persists. I lean much more towards the YAGNI principal instead. Having been in the industry for 20+ years it's my experience that it holds true more often than not.
I fail to see how layers help you scale to thousands of users. Doesn't that just mean scaling your servers up or out? You can do CA style by just creating three different folders in the same project and code against abstracts. I fail to see what benefit the different libraries really add besides complexity by having to move around different layers to introduce changes.
@@CodeOpinion you're lucky this has never happened to you. Being assured by the business that it's all they need only to be told later that it's not. I've been in software development for 20 years and it has happened in the past, so much so I just define layers and boundaries no matter what I'm developing because I know it is easier to adapt if inevitable change comes along
I get you. I get it. Patterns & principles always have exceptions. Of course. But when you speak of "context", mind that "context" also matter to the environment people work in. Let me address this with my example below. We are a small team with turnover every couple of years. And frankly, we all need to be able to take over a project instantly when someone is ill, or whatever... Ok, this addresses a structural problem of resources, but so be it, as IT I can scream & shout about it to increase resources. But if there are no budgets for that, then I won't get it. That's the context I have to code in, manage code in, manage complexity in, manage agility in... Although I always say to everyone, if your project is small, and CRUD, then don't mind - as you do. But I also say, think critically. Just "CRUD" doesn't mean "CRUD"' means no clean code. Often "business logic" creeps in. So, I tend to say, be pragmatic here, if you even sense the smell of it, then split it up please, so we can build upon it and don't need to refactor the whole code base as a small team.
Referring to the slide at 9:38, I'm not good at deciding where those cohesion dotted-line boundaries are. When a new feature needs to be added and it sits between two of those dotted-line boxes, which should it go into? Should there be cross dependency boundaries (probably not but recklessness in the moment seems like a good idea sometimes)? Should it become a new column in the diagram that depends on parts of the other two or does some redundant work?
@@CodeOpinion So just saw your video on that, thank for the informative content by the way, and I just want to clarify that getting rid of the inner modules by arch layer will result in vertical slices? That is how I understood it anyway. Will have to that. I stuck to having inner modules because that was what I had read but the inner modules seemed overkill esp if u have a one liner usecase, lol.
Layered architecture and clean architecture look same? Please help clarifying. How is Hexagonal architecture different from above? Also Dependency Inversion deserves its own video. Cheers!
Good suggestion. The difference are in the details, however they all come down to direction of dependencies and coupling and trying to keep the core business logic free of dependencies.
Great video! I just want to point out that what you call Infrastructure Layer is actually an Exposition or Export Layer. Infrastructure Layer should be bellow even the Domain Layer. It is the layer on which most of the other layers rely. Putting it above the application layer can be quite confusing. It may somehow be called infrastructure code but not infrastructure layer.
Did you really mean 5 routes == “only” 5 places to change code as a selling point against clean? I would much prefer only one place, perhaps two, to need to make a simple change! I agree clean is way overkill for most small to medium size apps. Would like to hear what architecture patterns are emerging that are a good fit for small apps (likely most apps).
Why is the layers breakdown in the Clean Architecture considered a "separation by technical concern"? That's something I disagree with yet I still hearing it over and over. To me, the point was always to focus on the domain and application, model it and then plug-in infrastructure. Why would it be "technical" concern?
If you look at the thumbnail and see projects of WebUI, Application, Infrastructure, Domain. Could you tell me what the app does? And then even dig into those folders, you'd see a "Services", "Persistence" , "Controllers", "Entities". Any idea what the app actually does yet? It does some technical stuff.
@@CodeOpinion Oh now I see and understand your point. However, when I implement the Clean Architecture with teams, right under "services" (or rather "use_cases" you can find some meaningful names that hint what the application does. I believe you think vertical slices are better at communication, because they can be named expressively? If so, then why not both? I combine these two that way. You can have named vertical slice and inside still split into application / domain etc (when it makes sense - not for CRUDs). Do you find such an approach flawed in any way? I'm curious about your opinion
You don't need the physical separation of a classlib/package if you can enforce it in code/convention. Some will say that's difficult so they enforce it by projects.
Class libraries are usefull when you want to deploy parts of your code seperatly. If you don't want to do that, just create one project and use folders to organize the code.
Great video! We have a mid size application where we are currently discussing these topics in terms of coupling and cohesion. The application is split into coherent domains, but they still have minor (1-2) dependencies to another domain. Since it's a monolith with shared database we are discussing how we could best deal with retrieval of data. On one hand, domains could request referenced data from each other through an interface - this would make the domains more decoupled but it would also require more code and maintainence. Another option is to have a shared persistence/DA layer which holds all entitles to be persisted and repository implementations. This would increase the coupling, but allow for easier queries as we could simply join if we need to find out the name of an Owner who is referenced on our House entity f.ex. Any ideas or tips on how to approach this?
If in a monolith, expose interfaces/delegates to get shared data. I'd be curious why the data is needed though. If it's for view/query composition purposes, sure. If it's for business logic, I'd question why its not within the boundary that requires.
@@CodeOpinion Appreciate the answer! The use of an interface to retrieve cross domain data would only be for view/query purposes, the entities needed for business logic are defined in the domain. I.e domain 1 would request data from domain 2 in order to fulfil a viewmodel requested from domain 1. Fairly new to the channel and love the content, so maybe this is covered in a previous video, if so I will get to it eventually :)
I do have aquestion please.Why infrastructure depends on Application Layer. I Often use call infrastructure from App Layer ex calling repositiries or infrastrcture service as email senders and so on.Thank you!
It's typically because the application shouldn't actually care how the infrastructure is implemented. The application layer can still call into infrastructure code though.The application layer defines an interface, and the infrastructure layer implements that interface.
A common way I've seen this done is to define infrastructure interfaces in the app layer and then implement them in the infrastructure layer. Your app layer would define an IRepository or IEmailSender type and your infrastructure layer would provide the DapperRepository implementation, for example. It's kind of a loophole in the 'dependencies facing inwards' model IMO, but the alternative would be having a bunch of glue logic in the UI. Clean architecture gets messy pretty quickly once you try to apply it to anything more than a simple demo app.
You don't have direct dependencies, you still code against abstractions. It's just that the implementations of those abstractions doesn't have to reside in another library/layer, it can just be a subfolder in the same feature folder. Only time I split up into other libraries is when I need to introduce some background workers like lambdas that need to access the same domain.
Полностью не согласен. 1. Чтобы разбить по фичам - нужен реально хороший доменный эксперт, которого в большинстве случаев - нет. Обычный подход к разработке: маркетинг решил завоевывать направление, программисты - сделайте что-то, что захватит этот рынок, а мы будем продавать. В аутсорсе - доменный эксперт на стороне, у него своих дел полно и он просто не хочет/не может погружаться достаточно в проект. Потому нужно заранее подготовить структуру проекта так, чтобы ваши "фичи" можно было перетасовать и доработать. С чистой архитектурой это сделать проще, потому что как раз все распихано по сервисам, лежит на доменном уровне и т.д. а потому - вы просто, если надо, меняете слой представления, слегка меняете сервисы и все. 2. Приложения растут, фичи начинают друг на друга накладываться. Вот, сегодня просто надо было CRUD с TODO, а завтра - это превратилось в полноценную систему управления проектами, которая еще и интеграцию со всем чем только можно, еще и кофе менеджеру может сварить. А менять всю структуру проекта каждые несколько месяцев - это всегда плохая идея (кто-то был в отпуске, вернулся, и не понимает, где та часть кода, над которой он работал) 3. Тестировать проще слой приложения, когда он лежит в отдельном пакете/модуле/проекте и не зависит от инфраструктуры и прочего. Вы можете все зависимости замокать и просто проверять именно что логику приложения. 4. Кучу раз слышал про интересные истории, что инфраструктура редко меняется, а потому - зачем закладываться под изменения (лишние абстракции, да-да-да). Так вот. Мой опыт показывает - что это самообман. Банально, вы заложились что используете PostgreSQL, завтра попадается клиент, который зачем-то купил SQLServer за большие деньги и он хочет, чтобы пользовались им. Или вскрылся какой-то недостаток изначально выбранных решений (доросли и RabbitMQ уже не держит нужную нагрузку). Ну так вот. Если изначально не заложить в структуру и архитектуру проекта, что вы можете сменить что-то на нужном слое - потом сталкиваешься с тем, что нужно кранчить 24/7, чтобы успеть в срок сделать все. 5. Самое простое - непонятно, что должно быть только фичей, что должно быть общим. Короче. Я понимаю, что всех достала слоеная архитектура. Но пока что более удобного решения нет в разрезе индустрии. Для своих проектов - можно хоть в main все писать, и радоваться. Но если приходишь на новый проект, то лучше будет вот эта вот, чем какой-то непонятный зверь.
Often a great indicator of badly applied clean architecture is when you heavily rely on mocking for "unit tests". I'm particularly frustrated with a code base I'm working on at the moment for having a lot of NSubstitute mock 5+ services just to test a single method on a service. It's not really a black box unit test at that point because you need to intrinsically set the parameters of what happens inside the method being tested. This also often leads to long chains of calls that don't really do anything other than call down the stack of layers. And it makes the code base really inflexible.
Any refactoring takes 10x the amount of time fixing tests than actually modifying the code, in my experience. All tests are coupled to the implementations via these mock setups.. Mark Seemann has some nice articles about this that made me aware of this
Well, it depends what you need to test. If you have some if-statements and need to see if it's hit if response is X and not hit if it's Y then yea you need to mock it. However, you can also just integration test this by spinning up a WebApplicationFactory and mock the dependencies directly in the DI container. You won't assert that the mock is being called correctly but instead you would verify the API response for each scenario. Sort of a mix between functional and integration test of the services you control, while you mock out services you don't control like external API calls. There's also the nuget AutoFixture which can create all mocks for you automatically, it has a package for NSubstitute.
@@PelFox It really doesn't make sense to me to mock if you want to do it right, and mocks always just come off as a code smell to me. They indicate that an integration test should really be put in its place. And if you're only interested in testing the surrounding code, it should be split into separate testable methods that can actually be unit tested. However, in a realistic scenario, clean architecture almost necessitates mocks because the layers of indirection are too bothersome to set up for a test. Conversely, vertical slice architecture lets you unit test the behavior in isolation. You only care about dependencies for that particular behavior, not everything else some general service might require. The traceability (undervalued quality in my opinion) is much greater from story to implementation and consequent test. "Did I implement this right?" Well, the unit test says you did certain things right. Are they enough to satisfy the story? If yes, then any potential problem is a problem with the requirements specification. If no, then problems are do to missing tests ensuring requirements are fulfilled. We have a general problem in software engineering in terms of how we think of code as a box that talks to another box, be it communication between infrastructure components or layers of architecture. We don't really think in terms of problem solving. We only think about how we fit problems into solutions that we're already familiar with. Hence "clean" architecture. Nothing clean about it in my opinion. Just a bunch of boxes we try out damnedest to shoehorn into our mental modal of an "ideal" system where everyone thinks like a computer. Or, rather, how the general software engineer thinks.
@@buriedstpatrick2294 if you code correctly you should only need to unit test the middle pieces and integration test at the boundaries. Mocks are ok for the edges because the interconnects are tested elsewhere. It's mainly about testing "is this piece of code doing what it's supposed to given this input." Doing end to end tests are more expensive to do and more difficult to maintain. If you are testing all the pieces individually, and there is a layer of negotiation (contract) testing between them...then it will all work when put together.
It could be. It really depends on what the web/client does/is. It should be a part of some logical boundary. How you view that in dev or how it's deployed are different concerns.
Haven’t watched the video yet but just wanted to express how much I loathe clean architecture. It’s just too much of unneeded complexity over so many layers just to do simple stuffs. It’s just maddening. Sigh 😞 Vertical Slice architecture runs circles around it and needs more love than this mess.
When someone is paying you big bucks to build a crud app, you cannot simply build a crud app. You need to take all the design patterns you ever heard off, mix them into a Clean CQRS, event driven and eventually sourced DDD micro-services API with a server side rendered single page app on top, all hosted in a kubernetes cluster on azure. And that's how you convince yourself that your life makes any sense.
Mate, it is a great video but your voice pitch is a killer and makes it hard to listen to the video untill the end. You seem to be pretty nervous and rushing through the video. Just saying.
I'm not nervous. When I first noticed the comment I didn't realize for which video it was. I thought maybe it was one from years ago where I was. Interesting you think so.
The rushing part is interesting because I tend to gloss over some things because there is overlap in other videos I've posted. I'm hesitant to rehash the same ideas in every video.
If you've watched any of my other videos, you know I'm an advocate for vertical slices and focusing on features and organizing code that way. I didn't really mention them in this video directly but I plan on creating a video dedicated to it.
Your channel is a treasure. Literally! Also thank you for being so humble unlike some other youtubers.
@@anatolia23 Thanks! Glad you find the videos helpful!
Vertical Slice to the rescue!
I have done away with terms like "Clean Architecture", "Ports and Adapters" or "Hexagonal Architecture" and just call it by its family name: "Inverted Architecture" In the end, it is just a manifestation of Inversion of Control.
Well said, IOC, DI. Fundamentally it is these concepts being applied correctly
I would love to check the document of your essay if it's okay with you. Your reply to my separate comment about CA+vertical slices was held from being published so I only got a preview of it from my notifications, probably because it contained a link to the essay. Maybe having only the last part of the URL would circumvent the issue?
A shame I couldn't read the rest of it
@@lunify2814 indeed...it seems that youtube has some strange policies, when it comes to sharing information. I merely included my name on the platform with the little blue bird and a request to contact me there directly ...the name is "beamologist". Hope this reaches you....if not, I'll have to make a video :)
There are some important differences between the different architectural approaches with IoC.
Bob Martin discusses them in the last chapter of the Clean Architecture book.
@@rothbardfreedom Of course he would say that, otherwise there would be no book to sell. A wise man once said: "If you can put a label on it, someone in the marketing department is smiling"
I find that if you don't setup the appropriate layers first, you never do. I've come to distrust any talk of "this app will only do X" because they always grow and become monsters (without a clean architecture). By the time you realize the problem, you end up contemplating rewriting the app from scratch.
Thanks for the video. Love this channel.
Totally agree with this!
I'm a Solutions Architect and I constantly bang my head against a wall arguing with developers about why they dont need CQRS and DDD in a CRUD microservice. We double or even triple our development time (and testing) times because of it. We have a huge number of services and the majority of them are really simple REST API's with simple CRUD behaviour. But you open up the code and its layer after layer of abstraction for what is essentially a controller and some CRUD. Development times stretch out and individual microservices becoming overly complex for absolutely no reason other than to stick to the gold rules of "Clean Architecture". It drives me mad. Use the patterns and processes when they're relevant; not just because you've seen a video somewhere telling you its the best way to do everything..
You summarized the entire video 😂
A 'huge number of crud microservices' seems like a problem on its own imo.
@@Pretence01 - I probably should have been more clear "a huge percentage are CRUD services". Relative to the overall domain
The more one digs down into the subject of distributed systems, the more one discovers an intrinsic incompatibility with Active Record style state management, in favor of immutability (Event Sourcing/CQRS).
It doesn't really matter if or how many well-crafted defensive asynchronous patterns are implemented, in the end, one cannot stop time and in CRUD based "microservices", implying multiple sources of truth, there is always the risk that a source of truth is no longer relevant in relation to the messages in the queues (which are yet another source of truth). Given the CAP theorem, this means that if one service fails, the wise thing to do would be to bring the whole system down (and thus virtually "stopping time"). Does this make sense?
@Robert, what's your tech stack?
Sometimes, it's beyond cohesion. When your software is large enough, even smaller pieces that don't need a business layer should have a "dummy" one just to have a consistent approach accross the entire code base.
Sometimes, when you work on a first subsystem that is built in a certain way and then you go to work on another one within the same software that is built differently might be confusing. So sometimes it is good to have everything layed out the same so developers won't need to think about how this piece is made each time they need to work on something.
I do understand what you're getting at with being consistent in your codebase, but I do think we should give developers the benefit of the doubt and assume they can understand context. I do understand what you're getting at though, I just think we should expect more from developers not to just be cogs in a wheel and "feature machines".
I love myself a vertical slice. It makes things so much more intuitive and easier to work on.
so it's been 1 year.
How is it going with Vertical Slices?
That is why we chose Clean Architecture for building our boilerplate template, BlazorPlate.
More context matters. On large scale company where the turnover are high, with clean architecture people can make changes without understanding the whole system, so it's easier to get up and running. I think this is the main reason why it's so popular (also to deal with Product Manager who keeps changing requirements all the time)
I think of that 'core' as the only part that isn't disposable. UIs come and go, protocols change, but the business logic is what differentiates you.
Good vid! There is a nice middle ground between classical mess and clean architecture that people kinda forget about: Hexagonal architecture or ports/adapaters. You have a core project which kinda is like a combination of Domain and Application. You define all interfaces in the core: primary ports for services that want to use your core and secondary ports for the core to use external stuff. So for example you define an ICarRepository as a secondary port and have the implementation in the Persistence layer. The CarRepository implements the ICarRepository defined in core, but is an internal class. Via these ports you can attach any number external systems to the core. As long as all interfaces are defined in the core and all implementations are internal you can ensure that the core has no outward dependencies. If you want to lets say refactor from using Oracle to Dapper with MSSQL as your data access you just need to implement the same interfaces and can attach via the same port.
Thanks for the video! You say pretty much the same I was thinking about this pattern and it's over-usage in simple projects/services.
For smaller apps I tend to just take a traditional layered approach which makes any business specific code easier to separate, if any as the app grows.
LOVE your channel, straight to the point ,not avoid trouble
Thanks!
I think you hit the nail on the head. I love Clean Architecture, but I do think that it's popularity and subsequent misuse and over-application is a consequence of "blog driven development"
If someone really wants to understand Uncle Bob's "Clean Architecture", they need to just read his book and note a few of his Caveats:
1. It's an paradigm, not a recipe
2. There could be more layers or there could be fewer layers
3. Its not a packaging paradigm (but he details what you refer to as "horizontal" and "verticle" slices)
4. I'm pretty sure he even suggests that, as a paradigm, it's not practical for trivial projects
You brought up a *really* great point about separating the database layer from the entities layer. I think TODO lists are wholly impractical for anything but a beginners guide to MVC architecture; they simply fail to acknowledge the treacherous nature of entity relationships with respect to the separation of database layer and the entities layer.
I think your point about commingling the database layer and the entities layer for trivial applications needs to be taken to heart. I deeply appreciate that you referred to entities that bring nothing to the table as "pretendo entities" or whatever you called them #useless 😂
Great video.
In my experience, the benefits of implementing a standard for solution organizing (like this one) outweigh the cons. Having basic decisions out of the way (layers, naming, references) removes a lot of hand wringing and pontificating that happens at the beginning of a project and keeps people from reinventing the wheel over and over. Personally, I can’t stand moving from solution to solution and seeing inconsistencies. Clean architecture might be a little prescriptive. And naming and layering consistency across a portfolio of projects might be good enough for many.
Exactly. It's why I promote it too, as we are a small team with turnover every couple of years. And frankly, we all need to be able to take over a project instantly when someone is ill, or whatever... Ok, this addresses a structural problem of resources, but so be it. But that is part of "context" too.
Although I always say to everyone, if your project is small, and CRUD, then don't mind. But once it has any form of business logic (and some CRUD already has that - without you realising it sometimes), then split it up please, so we can build upon it and don't need to refactor the whole code base as a small team.
Context matters! Knowing when to apply Clean Architecture matters. A lot of supporting applications end up just dealing with single concern where you should never even consider it and where such technical layering is only gonna cause more overhead. Having cohesive set of business functionality is usually enough. I only apply Clean Archetecture patterns in business critical applications which are much larger. Having separate domain/aggregates which are not concerned by any tehcnical infrastructure is the only way to properly unit test core of the system. A lot of times I see large systems where business logic is tested through large and slow integration tests because the technical parts are not properly separated. This is where proper layering and direction of dependencies matter.
This hard separation via projects always makes me think of the explicit file ordering in fsharp. You can only depend on something that comes before it. This helps you think about what you are doing and makes looking for the important/independent code simple, since it's all at the top. It also prevents you from accidentally doing the wrong thing like coupling your domain objects to implementation details like http/database stuff as that will result in compiler errors. Presentation/implementation should be underneath/depend on the logic, not the other way around. Using projects for this separation feels like such a heavy solution.
At my job it's just what you describe: big projects divided in presentation/infra/app/domain, with countless of repositories and usecases. Most of it for what is just CRUD. Though I'm that familiair with vertical slices, this seems more like what we would actually want to keep things maintainable. Big fat chance introducing this though, since these layers are kind of holy around these parts :')
I'll be doing a video on Vertical Slices in more detail soon.
To me, this doesn't need a name, it's just good programming. That anybody would code something from the inside layers outwards just blows my mind. I mean, sure, maybe beginners do, but I would expect someone working in the field to have been taught this from the very beginning.
Think about the situation in that by 30 minutes crash course about CA lector gonna implement entire finical management system instead of to-do
Obviously everyone should took pattern and solutions based on need and problem they are facing as always it's depend
By over ten years experience as software engineer I'm gonna give you some advice
1-never do over engineering
2-chose solutions and patterns wisely
3-if your boss told you Go with CA, microservice ,eventsourcing or vise versa , accept that and don't argue
I find when working with microservices that each service is so small that this really isn't needed. They aren't using crud, they just usually only deal with a small number of types of request, often only a single RPC endpoint or brokered event.
If I had to split a service into 4 projects, I'd probably say it means it's doing too much.
You still need to know about dependencies, coupling, etc, but it's at the level of the services rather than the classes.
I personally love the fact that I can unit- test domain logics easily.
Doesn't CA coexist with vertical slices ensuring high cohesion while maintaining a clear dependency direction? From what I understood from uncle bob explaining CA, its sole purpose is dependency direction, while his screaming architecture is used in tandem, basically applying vertical slicing with entities as the base.
I would love to hear your thoughts
CA plays perfectly with vertical slices, the latter being more important IMO
Just found your channel and I am really grateful, it answers a lot of questions I always had about software architecture. Thanks
Great to hear!
There needs to be a balance between clean and expressive. So things need to be frequently reevaluated.
The theoretical benefits are true, but how often does it happen that we change the framework?
I agree with the other principles, but arguing about the framework independence point
Which framework? Like top web framework? database framework? It's not about if you're going to change it really, it's about how coupled are you to it. If you aren't and you need to change it, then doing so is relatively cheap in terms of time.
If a project or feature isn't large enough to have its own "sections" for each layer, we just stick them all in the same package. E.g. if the comment feature is small enough, all classes just go in com.whatever.comment. You can tell which layer things belong to largely by class name.
If it grows too large we split things out into their own sub-packages, but I find oftentimes we don't need to.
We also only follow a "clean-ish" architecture. In particular, we let the App layer have a more direct connection to the database. This is because of transactions and data consistency though. I've had some bad experiences and subtle bugs in the past when trying to abstract away transactions. Everything else is pretty straight-line clean architecture though.
I like that this video is basically Derrick slapping people who use patterns without knowing why.
Great video!
I'm a junior dev and a big architecture lover. Usally i just put an abstract between my service layer and database layer, organize my code by what goes together and what is the responsibility of each of my components( class, function, etc)
Legend! Love your content. Context matters a lot. Thanks
Glad you enjoyed it!
I agree with this in 100%. Great video.
Glad to hear it!
Honestly I agree with everything but I strongly encourage people to build MVVM when starting new project. Even if it's really simple project without any business. It's way more scalable and the practice has proved that people do not make simple ToDo apps anymore. And it's always good idea to have the base project done well to make easier to scale in future.
"I had to open up so many files to make a simple change" is not a meaningful complaint. The question is how difficult was it to make the change, how likely were you to break something else while making the change etc. If each file you opened it was straightforward and clear what change you need to make and you were able to make that change cleanly and easily in a safe and well-tested way that was unlikely to break anything else, then you've had the best possible experience regardless of how many files you've opened.
The biggest problem I have with n-layer architecture is not when there are too many files, but when there are far too few. I.e. when there are basically three massive files, one for controllers, one for "services" (business logic) and one for "repository" rather than splitting them up further by use case. I have no problem with layers, but I also want vertical slices. You can do both!
I would recommend splitting up by vertical use case, but even then I still recommend separating out by technical concern as well: dice it up both horizontal and vertical. The primary reason is that if you don't split it up both horizontally and vertically, you'll get an idiot junior who thinks they are super smart l33t coder and they've found a fantastic way to be "DRY" and "eliminate code duplication" by introducing a bunch of horrendous spaghetti coupling between different technical layers. Ensuring you're not allowed to cross between layers of abstraction in one file eliminates opportunities for idiot 20-something programmers to try to be clever.
"I had to open up so many files to make a simple change" is usually the kind of thing you hear from 20-somethings as they begin to realizing that enterprise programming is actually very boring when it's going well. They got excited about programming because they actually find it exciting to spot all of the shortcuts and optimizations you can achieve by jumping between levels of abstraction etc. They get excited about generic code, etc. You don't want that attitude anywhere near your codebase, when you are in your 30's you are happy to write mind-numbingly boring code and get your excitement after 5pm when you've gone home for the day early because everything is rock solid and working.
One note, I often think the "I had to open so many files" is because there's a lot of indirection, often times without value. Some folks really love layers of abstraction.
Please share complete poc example or any sample app with clean architecture using unitofwork and repository pattern. Not only verbal explanation.
Slightly out out topic question.
Lets say there is a modular monolith. Modules here are well defined and having good boundaries.
If one module has to trigger a state change in other module , it calls the interfaces exposed by the other module (COMMAND)
Let's say one module wants to lookup/query data of another module, should there be separate interfaces exposed by the other module (QUERY).
Should the other module prevent its internal, models from being exposed (public)?
In a microservice setup, (assuming each module becomes one service), they probably expose HTTP APIs to lookup/query data.
Wondering how that can be designed in modular monolith where everything runs under same process?
Cheers!
If you're crossing a boundary because you're doing view/ui/query composition, then expose some type of interface/delegate that's a contract. However, if you're doing some query to another boundary because you need that data to perform a write/command, I'd be curious if the data should live where it's required for that write/command.
@@CodeOpinion Lets say module A managers Users.. Module B has some Orders.
Most likely Orders would have the userId to refer to the user.
Let us say there is an ask to generate a "View/Projection" for Orders along with showing User Details like (Name , email id), in that case Module B probably has to fetch the user details from Module B.
Module would use the userIds that it has in its schema to fetch probably? There is no write activity. Just querying to generate reports.
Also, querying data from one module to perform a write in that module is a "Design Smell" for sure. :)
So safe to say in modular monoliths, for "reads/queries" , a module MUST expose contracts/interfaces for other modules to interact, even if it might be so tempting to access repository of other module directly
Amazing video with a clear explanation!
How would you recommend a Junior to start learning DDD and clean architecture?
I have added DDD because I see it in most places that describes clean architecture
Thanks!
No, thank you! 😀
Hey is your DDD/ES course available yet?
You've got my sub!!
Would you say that Clean Architecture is a rebranding of Hexagonal architecture? It seems that's what you described.
Clean Architecture is a mix of DDD + Hexagonal + Onion architectures, just with a different name
It's kind of in the details about the "how" but they are all very similar to me. Ultimately separating by technical concerns.
Clean Architecture has nothing to do with DDD in my view. You can "do DDD" with CA or Vertical Slices or whatever. If we're talking about domain modeling, UL, boundaries, that has nothing to do with CA.
Most "piles of turds" start out as small apps where people say "we don't need to be concerned about architecture because it's a small app". Then that small app grows and things are added to a system that lacks extensibility. Comparing any business application to a TODO app is apples to oranges. Of course, if your app is never expected to change, you don't need to consider that; and something that small can be rewritten within a couple of weeks. Business applications, if they're successful, do grow. Considering that (like anything else) ahead of time saves you time later. PPPPPP
Then those teams fails to see when complexity outgrows their solution and don't apply refactoring and dealing with tech debt as a part of each sprint.
It's no point introducing a big complex architecture if all you have is one database table to begin with. That's something you introduce when you actually need it. As long as you code against interfaces and follow SRP together with a high test coverage you are free to make changes at any time.
@@PelFox I agree. I didn't suggest introducing an architecture that doesn't make sense for a particular application. Just that there's a difference between not thinking about architecture (as one could do with a simple static app) and putting some thought into it up front - which some write off as unnecessary because of lack of foresight. After all, by definition architecture is hard to change later.
Great content! Subbed :)
The issue I have with most decisions I disagree with is that they almost always seem to be made because someone heard it was a good idea at some point, without understanding the problems it solves.
It might be the correct decision, but it's an uninformed one.
Business: Oh we just need a ToDo app. Later: Oh we now need the ToDo app to access a database. Much Later: So we need the ToDo app to be available to thousands of users and still needs to be performant.
Sometimes, just doing clean architecture from the start is wise. Especially if it has the potential to change.
The counter point is, in my experience, that has never been the case. No up front design or exploration/understanding could lead you to this. As I mentioned in the video, defining boundaries is absolutely #1 thing to get done. If complexity creeps up, it shouldn't be within a monstrosity of fat wide layers but in a specific boundary. In order to define boundaries you need to better understand the domain.
There is nothing stopping you doing "CA" in a single project, or even file. The concept of invertion of control still persists. I lean much more towards the YAGNI principal instead. Having been in the industry for 20+ years it's my experience that it holds true more often than not.
I fail to see how layers help you scale to thousands of users. Doesn't that just mean scaling your servers up or out? You can do CA style by just creating three different folders in the same project and code against abstracts. I fail to see what benefit the different libraries really add besides complexity by having to move around different layers to introduce changes.
@@PelFox if the data layer is abstracted in a data layer it can be replaced with a scalable data store
@@CodeOpinion you're lucky this has never happened to you. Being assured by the business that it's all they need only to be told later that it's not. I've been in software development for 20 years and it has happened in the past, so much so I just define layers and boundaries no matter what I'm developing because I know it is easier to adapt if inevitable change comes along
Better question: why is Clean Architecture popular mainly (only?) among C# developers?
I get you. I get it. Patterns & principles always have exceptions. Of course. But when you speak of "context", mind that "context" also matter to the environment people work in. Let me address this with my example below.
We are a small team with turnover every couple of years. And frankly, we all need to be able to take over a project instantly when someone is ill, or whatever... Ok, this addresses a structural problem of resources, but so be it, as IT I can scream & shout about it to increase resources. But if there are no budgets for that, then I won't get it. That's the context I have to code in, manage code in, manage complexity in, manage agility in...
Although I always say to everyone, if your project is small, and CRUD, then don't mind - as you do. But I also say, think critically. Just "CRUD" doesn't mean "CRUD"' means no clean code. Often "business logic" creeps in. So, I tend to say, be pragmatic here, if you even sense the smell of it, then split it up please, so we can build upon it and don't need to refactor the whole code base as a small team.
Agree'd.
Referring to the slide at 9:38, I'm not good at deciding where those cohesion dotted-line boundaries are. When a new feature needs to be added and it sits between two of those dotted-line boxes, which should it go into? Should there be cross dependency boundaries (probably not but recklessness in the moment seems like a good idea sometimes)? Should it become a new column in the diagram that depends on parts of the other two or does some redundant work?
Check out this video where I of worked though a problem. It might give you some ideas: ua-cam.com/video/Trl4--FO7Yo/v-deo.html
have read the code should be organized with outer modules by features and inner modules by clean arch layers.
That's one option. Another is vertical slices and organize code by features.
@@CodeOpinion So just saw your video on that, thank for the informative content by the way, and I just want to clarify that getting rid of the inner modules by arch layer will result in vertical slices? That is how I understood it anyway. Will have to that. I stuck to having inner modules because that was what I had read but the inner modules seemed overkill esp if u have a one liner usecase, lol.
Respect for this video
Layered architecture and clean architecture look same? Please help clarifying.
How is Hexagonal architecture different from above?
Also Dependency Inversion deserves its own video. Cheers!
Good suggestion. The difference are in the details, however they all come down to direction of dependencies and coupling and trying to keep the core business logic free of dependencies.
Great video!
I just want to point out that what you call Infrastructure Layer is actually an Exposition or Export Layer.
Infrastructure Layer should be bellow even the Domain Layer. It is the layer on which most of the other layers rely.
Putting it above the application layer can be quite confusing.
It may somehow be called infrastructure code but not infrastructure layer.
Did you really mean 5 routes == “only” 5 places to change code as a selling point against clean? I would much prefer only one place, perhaps two, to need to make a simple change! I agree clean is way overkill for most small to medium size apps. Would like to hear what architecture patterns are emerging that are a good fit for small apps (likely most apps).
Great video! Is the logical boundary akin to the concept of a bounded context in DDD?
Correct
cohesion is the missing keyword in clean architecture. from what I see clean architecture only care about loose coupling from technical layer 🤔
I wouldn't say loose coupling. Just a way to manage coupling.
Why is the layers breakdown in the Clean Architecture considered a "separation by technical concern"? That's something I disagree with yet I still hearing it over and over. To me, the point was always to focus on the domain and application, model it and then plug-in infrastructure. Why would it be "technical" concern?
If you look at the thumbnail and see projects of WebUI, Application, Infrastructure, Domain. Could you tell me what the app does? And then even dig into those folders, you'd see a "Services", "Persistence" , "Controllers", "Entities". Any idea what the app actually does yet? It does some technical stuff.
@@CodeOpinion Oh now I see and understand your point. However, when I implement the Clean Architecture with teams, right under "services" (or rather "use_cases" you can find some meaningful names that hint what the application does. I believe you think vertical slices are better at communication, because they can be named expressively? If so, then why not both? I combine these two that way. You can have named vertical slice and inside still split into application / domain etc (when it makes sense - not for CRUDs). Do you find such an approach flawed in any way? I'm curious about your opinion
Why would Infrastructure depend on Application? Very weird.
so where should we place grpc proto files ?
Those are contracts, so higher up the stack. Possibly application layer
Should we create project(classlib) for each layer or one project with multi folders for each layer?
Start wirh option b. Mpvong stuff to library later just means namespace change yoy can do swiftly
You don't need the physical separation of a classlib/package if you can enforce it in code/convention. Some will say that's difficult so they enforce it by projects.
Class libraries are usefull when you want to deploy parts of your code seperatly. If you don't want to do that, just create one project and use folders to organize the code.
Great video!
We have a mid size application where we are currently discussing these topics in terms of coupling and cohesion. The application is split into coherent domains, but they still have minor (1-2) dependencies to another domain. Since it's a monolith with shared database we are discussing how we could best deal with retrieval of data.
On one hand, domains could request referenced data from each other through an interface - this would make the domains more decoupled but it would also require more code and maintainence. Another option is to have a shared persistence/DA layer which holds all entitles to be persisted and repository implementations. This would increase the coupling, but allow for easier queries as we could simply join if we need to find out the name of an Owner who is referenced on our House entity f.ex.
Any ideas or tips on how to approach this?
If in a monolith, expose interfaces/delegates to get shared data. I'd be curious why the data is needed though. If it's for view/query composition purposes, sure. If it's for business logic, I'd question why its not within the boundary that requires.
@@CodeOpinion Appreciate the answer! The use of an interface to retrieve cross domain data would only be for view/query purposes, the entities needed for business logic are defined in the domain.
I.e domain 1 would request data from domain 2 in order to fulfil a viewmodel requested from domain 1.
Fairly new to the channel and love the content, so maybe this is covered in a previous video, if so I will get to it eventually :)
Hi, Derek thanks a lot for your nice videos.
Do you know some very beginning course for clean architecture and DDD principles to suggest?
I'm working on one.. not so much clean architecture, more about base level architecture which includes some concepts from DDD.
Can't wait...!!
@@CodeOpinion thanks.
We appreciate you. God bless you
I do have aquestion please.Why infrastructure depends on Application Layer. I Often use call infrastructure from App Layer ex calling repositiries or infrastrcture service as email senders and so on.Thank you!
It's typically because the application shouldn't actually care how the infrastructure is implemented. The application layer can still call into infrastructure code though.The application layer defines an interface, and the infrastructure layer implements that interface.
A common way I've seen this done is to define infrastructure interfaces in the app layer and then implement them in the infrastructure layer. Your app layer would define an IRepository or IEmailSender type and your infrastructure layer would provide the DapperRepository implementation, for example. It's kind of a loophole in the 'dependencies facing inwards' model IMO, but the alternative would be having a bunch of glue logic in the UI. Clean architecture gets messy pretty quickly once you try to apply it to anything more than a simple demo app.
@@CoreCommander2 Yep that's how I do it
Out of interest, how would you handle unit testing in the instance of a service/ slice that uses direct dependencies?
You don't have direct dependencies, you still code against abstractions.
It's just that the implementations of those abstractions doesn't have to reside in another library/layer, it can just be a subfolder in the same feature folder.
Only time I split up into other libraries is when I need to introduce some background workers like lambdas that need to access the same domain.
@@PelFox I see, my misunderstand of the video - I’ve fallen into doing what you mention more and more often as of late. Definitely improves cohesion!
Great opinion.
Полностью не согласен.
1. Чтобы разбить по фичам - нужен реально хороший доменный эксперт, которого в большинстве случаев - нет. Обычный подход к разработке: маркетинг решил завоевывать направление, программисты - сделайте что-то, что захватит этот рынок, а мы будем продавать. В аутсорсе - доменный эксперт на стороне, у него своих дел полно и он просто не хочет/не может погружаться достаточно в проект. Потому нужно заранее подготовить структуру проекта так, чтобы ваши "фичи" можно было перетасовать и доработать. С чистой архитектурой это сделать проще, потому что как раз все распихано по сервисам, лежит на доменном уровне и т.д. а потому - вы просто, если надо, меняете слой представления, слегка меняете сервисы и все.
2. Приложения растут, фичи начинают друг на друга накладываться. Вот, сегодня просто надо было CRUD с TODO, а завтра - это превратилось в полноценную систему управления проектами, которая еще и интеграцию со всем чем только можно, еще и кофе менеджеру может сварить. А менять всю структуру проекта каждые несколько месяцев - это всегда плохая идея (кто-то был в отпуске, вернулся, и не понимает, где та часть кода, над которой он работал)
3. Тестировать проще слой приложения, когда он лежит в отдельном пакете/модуле/проекте и не зависит от инфраструктуры и прочего. Вы можете все зависимости замокать и просто проверять именно что логику приложения.
4. Кучу раз слышал про интересные истории, что инфраструктура редко меняется, а потому - зачем закладываться под изменения (лишние абстракции, да-да-да). Так вот. Мой опыт показывает - что это самообман. Банально, вы заложились что используете PostgreSQL, завтра попадается клиент, который зачем-то купил SQLServer за большие деньги и он хочет, чтобы пользовались им. Или вскрылся какой-то недостаток изначально выбранных решений (доросли и RabbitMQ уже не держит нужную нагрузку). Ну так вот. Если изначально не заложить в структуру и архитектуру проекта, что вы можете сменить что-то на нужном слое - потом сталкиваешься с тем, что нужно кранчить 24/7, чтобы успеть в срок сделать все.
5. Самое простое - непонятно, что должно быть только фичей, что должно быть общим.
Короче. Я понимаю, что всех достала слоеная архитектура. Но пока что более удобного решения нет в разрезе индустрии. Для своих проектов - можно хоть в main все писать, и радоваться. Но если приходишь на новый проект, то лучше будет вот эта вот, чем какой-то непонятный зверь.
Often a great indicator of badly applied clean architecture is when you heavily rely on mocking for "unit tests". I'm particularly frustrated with a code base I'm working on at the moment for having a lot of NSubstitute mock 5+ services just to test a single method on a service. It's not really a black box unit test at that point because you need to intrinsically set the parameters of what happens inside the method being tested. This also often leads to long chains of calls that don't really do anything other than call down the stack of layers. And it makes the code base really inflexible.
Any refactoring takes 10x the amount of time fixing tests than actually modifying the code, in my experience. All tests are coupled to the implementations via these mock setups.. Mark Seemann has some nice articles about this that made me aware of this
Well, it depends what you need to test. If you have some if-statements and need to see if it's hit if response is X and not hit if it's Y then yea you need to mock it.
However, you can also just integration test this by spinning up a WebApplicationFactory and mock the dependencies directly in the DI container.
You won't assert that the mock is being called correctly but instead you would verify the API response for each scenario. Sort of a mix between functional and integration test of the services you control, while you mock out services you don't control like external API calls.
There's also the nuget AutoFixture which can create all mocks for you automatically, it has a package for NSubstitute.
@@PelFox It really doesn't make sense to me to mock if you want to do it right, and mocks always just come off as a code smell to me. They indicate that an integration test should really be put in its place. And if you're only interested in testing the surrounding code, it should be split into separate testable methods that can actually be unit tested.
However, in a realistic scenario, clean architecture almost necessitates mocks because the layers of indirection are too bothersome to set up for a test.
Conversely, vertical slice architecture lets you unit test the behavior in isolation. You only care about dependencies for that particular behavior, not everything else some general service might require. The traceability (undervalued quality in my opinion) is much greater from story to implementation and consequent test. "Did I implement this right?" Well, the unit test says you did certain things right. Are they enough to satisfy the story? If yes, then any potential problem is a problem with the requirements specification. If no, then problems are do to missing tests ensuring requirements are fulfilled.
We have a general problem in software engineering in terms of how we think of code as a box that talks to another box, be it communication between infrastructure components or layers of architecture. We don't really think in terms of problem solving. We only think about how we fit problems into solutions that we're already familiar with. Hence "clean" architecture. Nothing clean about it in my opinion. Just a bunch of boxes we try out damnedest to shoehorn into our mental modal of an "ideal" system where everyone thinks like a computer. Or, rather, how the general software engineer thinks.
@@buriedstpatrick2294 if you code correctly you should only need to unit test the middle pieces and integration test at the boundaries. Mocks are ok for the edges because the interconnects are tested elsewhere. It's mainly about testing "is this piece of code doing what it's supposed to given this input." Doing end to end tests are more expensive to do and more difficult to maintain. If you are testing all the pieces individually, and there is a layer of negotiation (contract) testing between them...then it will all work when put together.
I think it's too much in one project file, couldn't the web ui be in a separate git repository all together?
It could be. It really depends on what the web/client does/is. It should be a part of some logical boundary. How you view that in dev or how it's deployed are different concerns.
Haven’t watched the video yet but just wanted to express how much I loathe clean architecture. It’s just too much of unneeded complexity over so many layers just to do simple stuffs. It’s just maddening. Sigh 😞
Vertical Slice architecture runs circles around it and needs more love than this mess.
I'll be creating a video about Vertical Slices. I have in the past but due for a new one.
any todo app or logging implementation as a demo is utterly useless
I don't think they are useless, the issue is people using them as templates for equally simplistic apps as the demo.
I agree with everything you said, but I feel like you're pushing a little too hard against CA. Potentially harder than you intend.
Interesting, I actually thought I wasn't pushing as much as I intended before I recorded it!
When someone is paying you big bucks to build a crud app, you cannot simply build a crud app. You need to take all the design patterns you ever heard off, mix them into a Clean CQRS, event driven and eventually sourced DDD micro-services API with a server side rendered single page app on top, all hosted in a kubernetes cluster on azure. And that's how you convince yourself that your life makes any sense.
Nice ant x)
Ehhhhh...
Canada?
Mate, it is a great video but your voice pitch is a killer and makes it hard to listen to the video untill the end. You seem to be pretty nervous and rushing through the video. Just saying.
I'm not nervous. When I first noticed the comment I didn't realize for which video it was. I thought maybe it was one from years ago where I was. Interesting you think so.
The rushing part is interesting because I tend to gloss over some things because there is overlap in other videos I've posted. I'm hesitant to rehash the same ideas in every video.
the comment makes no sense. there's no nervousness here. seems they're trolling.