This live stream series is A LOT, so I distilled everything we learned + built a proper demo app that's open source into a 53 minute tutorial: ruclips.net/video/jJVAla0dWJo/видео.html
My dude, i am a self taught junior developer and whilst i can write clean code, after 2 years now i realized how our apps we / i am working on have 0 architecture, 0 high level thought, and they are a complete mess on this level and the problems they bring. And it seems my peers are absolutely oblivious to this as they did not signal this and also we never had an 'architectural discussion' ( if that is even something happening at other places :D ), and as such i have no direct peer to learn from. So these kind of videos are gems inside the superficial hello world application videos most of youtube is filled with.
Woah this series took off! I'm happy you all like it! Hope you enjoy this series, and don't forget to subscribe to get notified when I post more content! Thank you all 💖
I was looking for a nextjs clean architecture in-depth setup, i really appreciate this series I will check it out thanks to youtube algo. A small suggestion would be adding chapters to your live streams after they're done. Thanks a bunch!
@@NaniwaRocky Thanks for the suggestion, and I'm glad you liked it! I'll look into adding chapters, but nevertheless, there's going to be a proper RUclips course on how to achieve this, and it won't be HOURS of content 😅
Just so you know for the future: when passing arguments to constructors in TS, you can automatically assign them to properties on the class with a syntax like `constructor(private id: string) {}` -- that way you don't have to repeat both the property definition and the assignment.
Thanks! I'll publish a demo project that implements everything we'd go through in this stream, plus a more polished proper RUclips tutorial that's shorter than the live streams 😁
There will be. As soon as I'm done figuring things out (this stream is me figuring things out) I plan on recording a proper RUclips tutorial that's shorter than the live streams and also publish a demo repository as well!
Just started watching this, great topic to dive into btw. Just wanted to say I am not a huge fan of not using a test database because the mock data can become stale, where as a test database should always be 1:1 with the dev schema at least. Would love some opinions though.
This would be an interesting problem to figure out. Curious to hear how would you set up testing with a database. What I'm thinking of is spinning up a docker compose config that sets up a pre-seeded db alongside the tests service and tear it down once the testing is done. I'm not 100% sure how would I set up the tearing down trigger though, but it could be cool to play around with that. How would you set this up?
@@nikolovlazarsound interesting. I think there is several level of testing abstraction and it might suitable for kinda mock e2e test. I belive that maintainability for the test is very important
Very cool video. I had a doubt, you talk about the persistence layer taking a input and giving an output without authorization, Can a user just bypass the Bussiness Layer and directly call the persistence layer because I can track the requests using the networks tab in developer options?
A user can't bypass the business layer because the only touch point with the backend is the route handler (or server action). A developer can bypass the business layer and directly use the persistence APIs, but there's nothing you can do to prevent that (maybe you could with a monorepo and a good dependency config).
Bro , you are amazing keep going , this series is what we really need , javascript ecosystem is not clean hhh or we don't know how to organize things , not like c# devs
My only question is on generating nanoid. In the repository layer we are tightly coupling our persistence/data layers with a package. Please correct me if I am wrong, wouldn’t it be better if we pass that package through the constructor as a service so that it is not tightly coupled to the library?
It’s perfectly fine that the repository implements specific libraries. Nanoid could additionally be isolated in its own service, but I deemed it might be an overkill for this scenario.
Hi, for the error handling do you usually throw errors in every layer? Where do you catch them, do you wrap the top level layer in try{}catch{} block or do you let nextjs take care of rendering the error page fallback? Error handling seems so subjective :C Great video btw it's so nice to see other people struggling in live session coding because all tutorias make it look like it's clean and perfect all the time lol
I would like to have the answer of this question. I am also having trouble handling errors. Did you find the optimum solution to this or close to optimum?
We’ll try to figure that out in the next stream (today!). I’m going to be setting up Sentry in this project, so every non-catched (and even some catched ones) will end up being sent to Sentry. When it comes to handling them, I found that services should throw, but actions should return objects so the UI can provide feedback to the user.
@@nikolovlazar Yes, and I assume that the persistance/db layer throws errors under the supabase api when anything out of the normal happens. Also makes sense actions return an object, and in that case, do you make sure every time you return the same shape of object like follwing a contract with discriminate unions or something of the style? Thank you, looking forward the next stream! This has been very insightful!
@@Luisllaboj19 Yep! The "zsa" package allows us to define the output just as like we define the input. I do have an example for this that I will showcase at the very beginning of the stream today.
I definitely see the value in this, but for my new MVP this might be an overkill atm, but once its launched and others start working with me then this would make absolute sense, less files edited, more concise folder structures. this makes sense actually. Ill need to take some time to organize it like this.
I also think that's the way to go. If you're starting a new project from zero, don't pay too much attention to this until you reach MVP state, or have validated the idea. Once things get serious, or other people join the project, it's definitely a good idea to establish either CA or a similar architecture so everyone's "talking" the same language. Even code reviews are faster when everyone writes code in a common predictable way. Not to mention, but debugging is faster as well. You'll know where you need to look at.
Hi, thanks for the great tutorial and series. Really enjoying it. Small problem I had watching was would have been nice if it was from scratch so we (i could code along) as you explained things. like the structure, creating of some of those files, but I still enjoyed it. h
Glad you enjoyed it! I do have a more concentrated tutorial that you can check out here: ruclips.net/video/jJVAla0dWJo/видео.html this one too doesn’t cover starting from scratch, but it’s showcasing clean architecture on top of a smaller GitHub project.
I came to review concepts, hopefully later we can see a complete auth system with the backend and frontend to see the entire flow with architecture, how to handle everything with jwt and so on.
I had to because creating it once in the constructor didn't take into consideration the session for each request. Maybe there is a way to only "refresh" or "reload" the session from the request, I just didn't look into it. But that's the reason.
I might have missed it in the video, but how do you plan on setting up/instantiating your services in page.tsx files and any other location that is not a server action? I did something similar to this on a vite-react project where I created a provider and had a hook that returned my services, but that's not really an option in server components.
@nikolovlazar it will be very intersting to implement the Hexagonal (Ports and Adapters) architecture on Next.js :) do you maybe have a plan to do that? Thanks, Men! appreciate your excellent work!!
Thanks! I don't have plans to do that, but it would be interesting. I was planning on doing this CA series and then move on to deploying the newly refactored Next.js app on Hetzner with Docker, and the whole setup with CI/CD, creating Docker images etc...
@@rahulprasad3575 It's a combination of Kitty config and Neovim config. Kitty's theme defines the background and everything outside of Neovim. Neovim only defines the syntax highlight colors, the contrast, etc... Kitty theme config: github.com/nikolovlazar/dotfiles/blob/main/.config/kitty/cyberdream.conf (mind the background - it's in the repo) Neovim theme config: github.com/nikolovlazar/dotfiles/blob/main/.config/nvim/lua/plugins/colorscheme.lua
This project is still close-sourced, but I do plan on making a proper, a more polished RUclips video with a demo project where I go through the same refactoring steps that I'll do in this series. That demo project will be minimal and contain only the relevant parts for the lesson, so it's going to be much cleaner and easier to understand. I'll post the video with the project on my channel, so keep an eye on it! 😁
@@nikolovlazar I'm waiting for that tutorial, I would love to learn how to implement this clean architecture with server actions in next js, great content ✨
No repo yet. This series is me figuring stuff out together with y'all, but I do plan on releasing a more polished, proper RUclips tutorial that's not N-hours long and that uses a demo project created specifically for it. That demo project will be open source.
No relying on underlying implementation is called abstraction - ruclips.net/video/BaUsKK6AX5Q/видео.html - its a fundamental concept in Software engineering. To make a more sense, your car is a better example, you don't need to know anything about how it works just to drive and use it for your needs 🤫
@@nikolovlazar yes for sure, and some more NextJS software tutorials right now you just have one the card, but we'd love a software as this one from scratch.
I am just watching this moment 1:25:48 , so maybe you've changed it later, but with typescript you can create a constructor like this constructor(private test: number) {} and it will automatically create a private property and assign the value to it :)
You're welcome! This project will most likely remain close sourced, but I'll be creating a different one (much simpler one) after this streaming series to showcase the architecture. I also plan on publishing a proper, more polished RUclips video on this topic that will use the demo project, so make sure to keep an eye on my channel!
@@iykazorji8171 I've attached a couple of phone holders below it so I can bring it to a 30 degree angle 😁 Here's how it looks like: www.reddit.com/r/zsaVoyager/comments/1dmrl4d/comment/l9xvmx1/
Min 3:16.. There are very important concepts that you are just misunderstanding. Layers is a different pattern. Just check!. Maybe DDD theory would help you understand much better the graphic that depicts Clear Architecture.Actually, the architecture you depicted is Classic Layers.
@@repinor I understand your point but keep in mind that you can look any archetcture such: Hexegonial, clean, onion as some layering archetcture. In general the most important thing is the separation and dependency.
@@chenrvn Indeed,, I agree that you should use design principles independly of what architecture style you use, however the approach it’s being explained here is conceptually wrong. You can not think DB and Web and Devices are in the same layer, even they could be “outside” they have complete level of visibility. Hexagonal Architecture and clean Architecture in my opinion are like a kind of composable architecture in which there are levels of privacy and visibility that plays a very clear role along the solution. My point is, you should use design principles like SOLID, DRY, KISS, YAGNI, OO principles, etc, but you can not confuse design principles with architectural styles. In my opinion the way Clean Architecture is approached here is being confused with Layers.
@@chenrvnBut, what is wrong with Layers? 1. Promotes Database Driven Design. 2. Hides use cases. 3.Makes parallel work difficult, 4. Grows hard to Test and I’d say that it’s prone to shortcuts. In the long run, it will happen, because, you know the speed of the business.
@@repinor it's a great concepts. I just say that you can think of clean architcture also as a "layer" archetcture. It depend how you determine it. All what you mention above is an excellent and proved concepts :-)
My toxic trait is thinking I could recreate your theme on Neovim lmao. It looks really fukin good but I remember spending weeks on mine and still turning out crap and made me 10x less productive.
You definitely shouldn't do this for every project, but as your project grows into complexity you'll find yourself needing to implement something like this.
This live stream series is A LOT, so I distilled everything we learned + built a proper demo app that's open source into a 53 minute tutorial: ruclips.net/video/jJVAla0dWJo/видео.html
My dude, i am a self taught junior developer and whilst i can write clean code, after 2 years now i realized how our apps we / i am working on have 0 architecture, 0 high level thought, and they are a complete mess on this level and the problems they bring. And it seems my peers are absolutely oblivious to this as they did not signal this and also we never had an 'architectural discussion' ( if that is even something happening at other places :D ), and as such i have no direct peer to learn from. So these kind of videos are gems inside the superficial hello world application videos most of youtube is filled with.
welcome
Woah this series took off! I'm happy you all like it! Hope you enjoy this series, and don't forget to subscribe to get notified when I post more content! Thank you all 💖
I was looking for a nextjs clean architecture in-depth setup, i really appreciate this series I will check it out thanks to youtube algo. A small suggestion would be adding chapters to your live streams after they're done. Thanks a bunch!
@@NaniwaRocky Thanks for the suggestion, and I'm glad you liked it! I'll look into adding chapters, but nevertheless, there's going to be a proper RUclips course on how to achieve this, and it won't be HOURS of content 😅
From web dev cody ✌️
WDC is GOAT 😁
Same
No one usually talks about this. Thanks man! I don't use Next anymore, but love learning architecture and DDD in general.
What do you use? 😎
Just so you know for the future: when passing arguments to constructors in TS, you can automatically assign them to properties on the class with a syntax like `constructor(private id: string) {}` -- that way you don't have to repeat both the property definition and the assignment.
Oh I did actually type them like that. A person in the chat reminded me. Thanks for the suggestion!
Thank you for that stream!
Your are just Professor Dumbledor form Harry Porter . Deep , Clean and Clear
Thats pretty cool video. Would be nice to have github repo to check how things are built. That would help a lot.
Thanks! I'll publish a demo project that implements everything we'd go through in this stream, plus a more polished proper RUclips tutorial that's shorter than the live streams 😁
1:35:48 Effect looks good. Is it just like Promise from fp-ts? I found that way of error handling easy and light weight.
It does look like it has a bit of learning curve, but I do think it's a really cool library!
Great stuff, would be awesome to have a demo repository with this architecture approach example :)
There will be. As soon as I'm done figuring things out (this stream is me figuring things out) I plan on recording a proper RUclips tutorial that's shorter than the live streams and also publish a demo repository as well!
Just started watching this, great topic to dive into btw. Just wanted to say I am not a huge fan of not using a test database because the mock data can become stale, where as a test database should always be 1:1 with the dev schema at least. Would love some opinions though.
This would be an interesting problem to figure out. Curious to hear how would you set up testing with a database. What I'm thinking of is spinning up a docker compose config that sets up a pre-seeded db alongside the tests service and tear it down once the testing is done. I'm not 100% sure how would I set up the tearing down trigger though, but it could be cool to play around with that. How would you set this up?
@@nikolovlazarsound interesting.
I think there is several level of testing abstraction and it might suitable for kinda mock e2e test.
I belive that maintainability for the test is very important
That keyboard loved it. :D
Very cool video. I had a doubt, you talk about the persistence layer taking a input and giving an output without authorization, Can a user just bypass the Bussiness Layer and directly call the persistence layer because I can track the requests using the networks tab in developer options?
A user can't bypass the business layer because the only touch point with the backend is the route handler (or server action). A developer can bypass the business layer and directly use the persistence APIs, but there's nothing you can do to prevent that (maybe you could with a monorepo and a good dependency config).
Great session man. I like your keyboard setup too 🔥😃
Thank you!
Bro , you are amazing keep going , this series is what we really need , javascript ecosystem is not clean hhh or we don't know how to organize things , not like c# devs
Thank you! Let's change that! 😁
Bro i start learning c# , can you suggest some resources ? In a clean architecture way @@nikolovlazar
Bro , can you explain clean architecture in c# , i started learning c# , its a beautiful language
Thank you 😁
Absoluetly love this. Thank you. Any chance of getting a neovim / tmux / terminal setup video?
I did start to put together some content on Neovim. It will be fun creating a video on my neovim setup and workflow.
We need more stuff like this, ❤
My only question is on generating nanoid. In the repository layer we are tightly coupling our persistence/data layers with a package. Please correct me if I am wrong, wouldn’t it be better if we pass that package through the constructor as a service so that it is not tightly coupled to the library?
It’s perfectly fine that the repository implements specific libraries. Nanoid could additionally be isolated in its own service, but I deemed it might be an overkill for this scenario.
Hi, for the error handling do you usually throw errors in every layer? Where do you catch them, do you wrap the top level layer in try{}catch{} block or do you let nextjs take care of rendering the error page fallback?
Error handling seems so subjective :C
Great video btw it's so nice to see other people struggling in live session coding because all tutorias make it look like it's clean and perfect all the time lol
I would like to have the answer of this question. I am also having trouble handling errors. Did you find the optimum solution to this or close to optimum?
We’ll try to figure that out in the next stream (today!). I’m going to be setting up Sentry in this project, so every non-catched (and even some catched ones) will end up being sent to Sentry. When it comes to handling them, I found that services should throw, but actions should return objects so the UI can provide feedback to the user.
@@nikolovlazar Yes, and I assume that the persistance/db layer throws errors under the supabase api when anything out of the normal happens. Also makes sense actions return an object, and in that case, do you make sure every time you return the same shape of object like follwing a contract with discriminate unions or something of the style? Thank you, looking forward the next stream! This has been very insightful!
@@Luisllaboj19 Yep! The "zsa" package allows us to define the output just as like we define the input. I do have an example for this that I will showcase at the very beginning of the stream today.
I definitely see the value in this, but for my new MVP this might be an overkill atm, but once its launched and others start working with me then this would make absolute sense, less files edited, more concise folder structures. this makes sense actually. Ill need to take some time to organize it like this.
I also think that's the way to go. If you're starting a new project from zero, don't pay too much attention to this until you reach MVP state, or have validated the idea. Once things get serious, or other people join the project, it's definitely a good idea to establish either CA or a similar architecture so everyone's "talking" the same language. Even code reviews are faster when everyone writes code in a common predictable way. Not to mention, but debugging is faster as well. You'll know where you need to look at.
Hi, thanks for the great tutorial and series. Really enjoying it. Small problem I had watching was would have been nice if it was from scratch so we (i could code along) as you explained things. like the structure, creating of some of those files, but I still enjoyed it. h
Glad you enjoyed it! I do have a more concentrated tutorial that you can check out here: ruclips.net/video/jJVAla0dWJo/видео.html this one too doesn’t cover starting from scratch, but it’s showcasing clean architecture on top of a smaller GitHub project.
Hey man, how did you achieve such smooth scrolling in your Neovim? Is it because of the Kitty terminal? Please share.
It's probably the quick repeat effect: github.com/nikolovlazar/dotfiles/blob/main/.zshrc#L52-L55
@@nikolovlazar Wowww! Thank you so much. You don't know how much I love this change. I did change it through the system settings, though.
thank you!
I came to review concepts, hopefully later we can see a complete auth system with the backend and frontend to see the entire flow with architecture, how to handle everything with jwt and so on.
Yes the course that I plan to release will use either next-auth or lucia, not Supabase.
@@nikolovlazar thanks
Could you please let me know why you are calling const supabase = createClient() for each function?
I had to because creating it once in the constructor didn't take into consideration the session for each request. Maybe there is a way to only "refresh" or "reload" the session from the request, I just didn't look into it. But that's the reason.
What do you think about using row level security?
I like the concept, but I still don't understand them fully. I need to spend some more time playing around with RLS. Any tips? 😁
niece session. you nicely teach.
Thank you Sajid! Glad you liked it!
Let's always do alot of good
what settings you are using for neovim can you please share your neovim config
Of course! Here's my dotfiles repo: github.com/nikolovlazar/dotfiles
I might have missed it in the video, but how do you plan on setting up/instantiating your services in page.tsx files and any other location that is not a server action? I did something similar to this on a vite-react project where I created a provider and had a hook that returned my services, but that's not really an option in server components.
We’re yet need to think about this.
What keyboard are you using? :D
Will you create a video about neovim how to install it and with your config? :D
It's the ZSA Voyager. It has been requested previously, so I might end up making a video on how I achieved this setup and what goes into it.
Subbed!! Came here from WDC 😊
@nikolovlazar it will be very intersting to implement the Hexagonal (Ports and Adapters) architecture on Next.js :)
do you maybe have a plan to do that?
Thanks, Men!
appreciate your excellent work!!
Thanks! I don't have plans to do that, but it would be interesting. I was planning on doing this CA series and then move on to deploying the newly refactored Next.js app on Hetzner with Docker, and the whole setup with CI/CD, creating Docker images etc...
BTW where do you put hooks in which layers?
Also make projects using DDD CQRS Event driven architecture
Exploring DDD on this channel would be cool. Thanks for the feedback!
Thanks :3
I also like I prefix for interface. basically I am dotnet software engineer.
Hello! I LOVED YOUR KEYBOARD! what is the model?
It's the ZSA Voyager!
Lazar, what code editor and theme are you using??
It’s Neovim, running within Kitty! Check out my config:
github.com/nikolovlazar/dotfiles
@@nikolovlazar how can i apply the same theme as yours from the dot files?
@@rahulprasad3575 It's a combination of Kitty config and Neovim config. Kitty's theme defines the background and everything outside of Neovim. Neovim only defines the syntax highlight colors, the contrast, etc...
Kitty theme config: github.com/nikolovlazar/dotfiles/blob/main/.config/kitty/cyberdream.conf (mind the background - it's in the repo)
Neovim theme config:
github.com/nikolovlazar/dotfiles/blob/main/.config/nvim/lua/plugins/colorscheme.lua
where I can find your code repository
This project is still close-sourced, but I do plan on making a proper, a more polished RUclips video with a demo project where I go through the same refactoring steps that I'll do in this series. That demo project will be minimal and contain only the relevant parts for the lesson, so it's going to be much cleaner and easier to understand. I'll post the video with the project on my channel, so keep an eye on it! 😁
@@nikolovlazar I'm waiting for that tutorial, I would love to learn how to implement this clean architecture with server actions in next js, great content ✨
Thanks 🙏
What is the book that you open along with?
Oh those are just my notes for the stream 😅 it's a plain notebook
is there any gh repo w the final code?
No repo yet. This series is me figuring stuff out together with y'all, but I do plan on releasing a more polished, proper RUclips tutorial that's not N-hours long and that uses a demo project created specifically for it. That demo project will be open source.
No relying on underlying implementation is called abstraction - ruclips.net/video/BaUsKK6AX5Q/видео.html - its a fundamental concept in Software engineering. To make a more sense, your car is a better example, you don't need to know anything about how it works just to drive and use it for your needs 🤫
That’s right!
Please create your development environment setup series
My Neovim setup? A few more folks have requested it as well, so I’ll definitely record a video on it!
@@nikolovlazar yes for sure, and some more NextJS software tutorials right now you just have one the card, but we'd love a software as this one from scratch.
Not sure if you've seen it, but I published a video on my dev environment setup a couple of days ago: ruclips.net/video/G7-qUMKSH_Y/видео.html
Please create you development environment setup series
Will do! A number of people have already requested that. I'll definitely publish a video on my dev environment. Keep an eye on my channel for it!
Also from web dev cody
Welcome WDC gang! 🙌
I am just watching this moment 1:25:48 , so maybe you've changed it later, but with typescript you can create a constructor like this
constructor(private test: number) {}
and it will automatically create a private property and assign the value to it :)
Oh nice! Thanks for the tip, Sebastian!
Thank you so much. Can you share the source code.
You're welcome! This project will most likely remain close sourced, but I'll be creating a different one (much simpler one) after this streaming series to showcase the architecture. I also plan on publishing a proper, more polished RUclips video on this topic that will use the demo project, so make sure to keep an eye on my channel!
@@nikolovlazarnice that would be helpful
Hey man are you from balkan originally? :D
Hey Srdjane! Yes I am 😁 I’m from Macedonia, but moved to Canada last year.
@@nikolovlazar Very nice, also very nice videos and content! Did you find a job and company helped you move?
Thanks! Yeah Sentry took care of my move.
What keyboards are those?!
It’s the ZSA Voyager!
@@nikolovlazar Oh it's the same I have just looked curved in the video!
@@iykazorji8171 I've attached a couple of phone holders below it so I can bring it to a 30 degree angle 😁 Here's how it looks like: www.reddit.com/r/zsaVoyager/comments/1dmrl4d/comment/l9xvmx1/
@@nikolovlazar Ah, thanks! Gonna try this out!
Min 3:16.. There are very important concepts that you are just misunderstanding. Layers is a different pattern. Just check!. Maybe DDD theory would help you understand much better the graphic that depicts Clear Architecture.Actually, the architecture you depicted is Classic Layers.
@@repinor I understand your point but keep in mind that you can look any archetcture such: Hexegonial, clean, onion as some layering archetcture.
In general the most important thing is the separation and dependency.
@@chenrvn Indeed,, I agree that you should use design principles independly of what architecture style you use, however the approach it’s being explained here is conceptually wrong. You can not think DB and Web and Devices are in the same layer, even they could be “outside” they have complete level of visibility. Hexagonal Architecture and clean Architecture in my opinion are like a kind of composable architecture in which there are levels of privacy and visibility that plays a very clear role along the solution. My point is, you should use design principles like SOLID, DRY, KISS, YAGNI, OO principles, etc, but you can not confuse design principles with architectural styles. In my opinion the way Clean Architecture is approached here is being confused with Layers.
@@chenrvnBut, what is wrong with Layers? 1. Promotes Database Driven Design. 2. Hides use cases. 3.Makes parallel work difficult, 4. Grows hard to Test and I’d say that it’s prone to shortcuts. In the long run, it will happen, because, you know the speed of the business.
@@repinor it's a great concepts.
I just say that you can think of clean architcture also as a "layer" archetcture. It depend how you determine it.
All what you mention above is an excellent and proved concepts :-)
My toxic trait is thinking I could recreate your theme on Neovim lmao. It looks really fukin good but I remember spending weeks on mine and still turning out crap and made me 10x less productive.
Go steal it! github.com/nikolovlazar/dotfiles
Nice video. But this is over complicated for most projects
You definitely shouldn't do this for every project, but as your project grows into complexity you'll find yourself needing to implement something like this.
Are you Bulgarian?
Nope, close 😁 I’m Macedonian. Pozdrav neighbour! 🙌