I've started working on a project using this architecture and the only drawback that I experienced was that because you are using dependency injection, it requires interfaces/types everywhere which prevents you from using type inference. Would love to see how you deal with this.
This is so dope and simplified .. If only this video existed last year it would've made my life much easier. The company I work for is using a very similar architecture for their backend (Onion Architecture) and trust me it was such a pain in the ass understanding it especially as a junior backend dev.
Bro!!! I'm in the same situation right now. Currently trying to implement this concept with Nest on my job. Actually I was able to understand the whole point of this pattern, but I'm lack of skills to to bring it to life at the moment.
Just wanted to add regarding DTO. You make a good point at 15:50 that if you own the front and backend, it is not difficult to refactor if schema changes. What I think you could have mentioned, is that when you depend on a third party API, converting the API response to an object you own allows for much easier updates in the future, as you wont be proliferating an object type you don't own to multiple layers. If the API ever changes what it returns or if you ever decide to change to a different API, that code change should be encapsulated in a single layer. Great video.
Yes, great explanation, thank you! Would definitely check out the project implementation of this principle. Even though, the logic is pretty clear and understandable, when it comes to rl projects, it can get kinda confusing sometimes. Even just deciding on folder structure etc. :/
I agree with most of the ideas stated in the video. I use this architecture to teach new recruits in the company i'm in. I like how it separates the 3 main layers (Http/logic/DB) that often composes a modern backend. For new software engineers it is easier to understand when it is separated between files.The only tricky part for me is on where you declare your DTOS/Entities. You stated here that they are inside the business logic (which is fine by me) but when you use ORM, having Dtos that are not similar to the database model can cause some typing issue. I know it shouldn't be the case as your SQL model should be clean but on legacy application where the database cannot easily be altered, its always a headache. I have to admit that to solve this issue i've been guilty of using the types declared by the database model in the business logic (mostly because of laziness). Great video nonetheless for beginners that want to take it a bit further and start to design a more scalable project !
Thank you for this great video. I was thinking about using i.e zod for the domain entities, that kinda violates the clean architecture since its a framework/library that is subject to change. But i guess using DI/interfaces/plain JS to remedy this is somewhat overkill.
Thanks for a great video! You mention in the end you'd make a video where you'd explain these concepts while coding a Next.js application. Did you ever release that video? Would be really interested in watching it. If so, could you maybe link it?
11:00 why is that? When you have an interface for your db logic, you theoretically could also just import the e.g. function and use it in the interactor as the interface stays the same regardless of the implemention. You would also achieve decoupling it from the interaction by the hiding the implementation behind that function. But am I getting this right: You should not import the interface in the interactor because you want to completely decouple it. By completely I mean not even import it and just use the controller to dependecy-inject it? Bc that's the role of the controller? So it is just a design thing, because as I said if I would directly import it, as the interface stays the same it wouldn't matter if I dependency-inject or import it. I would achieve the same decoupilation. An answer would be very appreciated!
Because you’re coupled to the location of the module in the filesystem, if the module exports a names export or a default export, also you’re coupled to the implementation and not the interface. It’s hard to explain when using JavaScript since everything is an implied interface, but in typescript your code would depend on the interface and the implementation would be injected. So imagine this, I have an api that have 100 endpoints that all need to read and write to Amazon s3. They all import a uploadFile method from a file inside a directory called persistence/s3.js. Now what if aws decided to charge 5x more for their s3 service and you want to switch to something else? You’d need to search through all of your files and manually change the import path to load a new file called persistence/other.js. It’s a Lot of work for a simple change. If that was instead injected, you could just change the implementation in a single location of your code base and you’d be done. The idea is to make code easier to refactor. You might not always need it, but when something big occurs and business needs you to make a fast refactor, it helps to keep your business logic decoupled from the lower level details of how stuff is stored on the db or file storage, etc
@@WebDevCody thx for the answer and your time I understood everything but I want to make one point clear. So you're saying that if I would inject it I would only need to change the implementation at one point. But that has to mean that you also have to create a facade / wrapper for it. So in your uploadFile example - if I would inject it to the interactions from e.g. the controller instead of importing it within the interaction file, I decoupled it compIetely from the business logic and have the possibility in the controller to inject it at runtime with a use of e.g. an other library or implementation. But if I would change the library now, the rename work would just be lifted up to the controller layer - EXCEPT I create a facade / wrapper for it that uses the library and returns the proper interface implementation. So now you would have a single source of truth I guess.
All you need to do, is ask yourself if this is an implementation detail of the persistence layer, or part of the higher level api you are exposing trough types or interfaces to an upper layer. That should give you the answer.
You aren't a big fan of Uncle Bob? He coined clean code principles and is one of the authors of "Manifesto for Agile Software Development". The man is a living legend. I don't think you realize his massive influence on the software development industry.
This is what happens when people first learn about design patterns.. full gas no brakes. then after a couple of years they realize oop is shit and they return to procedual as they realize nobody wants to maintain their shit hole.
Woukd love to see a backend project with same implementation
+1
Good idea!
+ 1
I want a nestjs whit this implementation
great work man, would be epic if you could build a full stack application with all these great practices
I was just looking up clean architecture for the first time, early this week. Thanks for making a video.
Very clear explanation! Thank you for clearing up some of my confusion
I've started working on a project using this architecture and the only drawback that I experienced was that because you are using dependency injection, it requires interfaces/types everywhere which prevents you from using type inference. Would love to see how you deal with this.
it is just tradeoffs that need to be accepted if using decopled layered architecture like this.
This is so dope and simplified .. If only this video existed last year it would've made my life much easier. The company I work for is using a very similar architecture for their backend (Onion Architecture) and trust me it was such a pain in the ass understanding it especially as a junior backend dev.
Bro!!! I'm in the same situation right now. Currently trying to implement this concept with Nest on my job. Actually I was able to understand the whole point of this pattern, but I'm lack of skills to to bring it to life at the moment.
Just wanted to add regarding DTO. You make a good point at 15:50 that if you own the front and backend, it is not difficult to refactor if schema changes. What I think you could have mentioned, is that when you depend on a third party API, converting the API response to an object you own allows for much easier updates in the future, as you wont be proliferating an object type you don't own to multiple layers. If the API ever changes what it returns or if you ever decide to change to a different API, that code change should be encapsulated in a single layer.
Great video.
Yes, great explanation, thank you! Would definitely check out the project implementation of this principle. Even though, the logic is pretty clear and understandable, when it comes to rl projects, it can get kinda confusing sometimes. Even just deciding on folder structure etc. :/
This video is eye opening thank you !!
I agree with most of the ideas stated in the video. I use this architecture to teach new recruits in the company i'm in. I like how it separates the 3 main layers (Http/logic/DB) that often composes a modern backend. For new software engineers it is easier to understand when it is separated between files.The only tricky part for me is on where you declare your DTOS/Entities. You stated here that they are inside the business logic (which is fine by me) but when you use ORM, having Dtos that are not similar to the database model can cause some typing issue. I know it shouldn't be the case as your SQL model should be clean but on legacy application where the database cannot easily be altered, its always a headache. I have to admit that to solve this issue i've been guilty of using the types declared by the database model in the business logic (mostly because of laziness). Great video nonetheless for beginners that want to take it a bit further and start to design a more scalable project !
some actual example of code structure would be awesome
Thank you for this great video. I was thinking about using i.e zod for the domain entities, that kinda violates the clean architecture since its a framework/library that is subject to change. But i guess using DI/interfaces/plain JS to remedy this is somewhat overkill.
I think it’s fine. If the rules are too strict you’ll spend more time reimplementing a validation library that actually shipping software
Been waiting for this. Thanks!
Thanks for a great video! You mention in the end you'd make a video where you'd explain these concepts while coding a Next.js application. Did you ever release that video? Would be really interested in watching it. If so, could you maybe link it?
Love this type of content, would love to see a fresh t3 stack tutorial vid
Did you also create a Clean architecture Video for frontend?
Hey, with monorepo approach You can create lib with api-interfaces (if front-back are e.g. only TS). Great content
11:00 why is that?
When you have an interface for your db logic, you theoretically could also just import the e.g. function and use it in the interactor as the interface stays the same regardless of the implemention.
You would also achieve decoupling it from the interaction by the hiding the implementation behind that function.
But am I getting this right:
You should not import the interface in the interactor because you want to completely decouple it. By completely I mean not even import it and just use the controller to dependecy-inject it?
Bc that's the role of the controller? So it is just a design thing, because as I said if I would directly import it, as the interface stays the same it wouldn't matter if I dependency-inject or import it. I would achieve the same decoupilation.
An answer would be very appreciated!
Because you’re coupled to the location of the module in the filesystem, if the module exports a names export or a default export, also you’re coupled to the implementation and not the interface. It’s hard to explain when using JavaScript since everything is an implied interface, but in typescript your code would depend on the interface and the implementation would be injected. So imagine this, I have an api that have 100 endpoints that all need to read and write to Amazon s3. They all import a uploadFile method from a file inside a directory called persistence/s3.js. Now what if aws decided to charge 5x more for their s3 service and you want to switch to something else? You’d need to search through all of your files and manually change the import path to load a new file called persistence/other.js. It’s a Lot of work for a simple change. If that was instead injected, you could just change the implementation in a single location of your code base and you’d be done.
The idea is to make code easier to refactor. You might not always need it, but when something big occurs and business needs you to make a fast refactor, it helps to keep your business logic decoupled from the lower level details of how stuff is stored on the db or file storage, etc
@@WebDevCody thx for the answer and your time I understood everything but I want to make one point clear.
So you're saying that if I would inject it I would only need to change the implementation at one point. But that has to mean that you also have to create a facade / wrapper for it. So in your uploadFile example - if I would inject it to the interactions from e.g. the controller instead of importing it within the interaction file, I decoupled it compIetely from the business logic and have the possibility in the controller to inject it at runtime with a use of e.g. an other library or implementation. But if I would change the library now, the rename work would just be lifted up to the controller layer - EXCEPT I create a facade / wrapper for it that uses the library and returns the proper interface implementation. So now you would have a single source of truth I guess.
I'm a bit confused, where should I put the transaction, commit, and rollback?
I’d have to think about that
All you need to do, is ask yourself if this is an implementation detail of the persistence layer, or part of the higher level api you are exposing trough types or interfaces to an upper layer. That should give you the answer.
Good job babe!!!
ForEach then Clean Architecture, nice ))
Go from each end of the experience spectrum lol
This looks to me as N-Tier architecture. E.g. the presentation tier, logic tier, and data tier. Please correct me if I am wrong.
You aren't a big fan of Uncle Bob?
He coined clean code principles and is one of the authors of "Manifesto for Agile Software Development". The man is a living legend. I don't think you realize his massive influence on the software development industry.
I guess I’m just put off by his book. I don’t like his writing style. But yeah he has done great things for the industry for sure
A.K.A Java hell.... NotLikeThis
It ain’t that bad.
This is what happens when people first learn about design patterns.. full gas no brakes. then after a couple of years they realize oop is shit and they return to procedual as they realize nobody wants to maintain their shit hole.