How I structure my next.js applications
Summary
TLDRThe video script discusses the importance of code structure and architecture in software development, particularly for a Next.js starter kit. The speaker advocates for a layered architecture approach, inspired by 'Clean Architecture' by Uncle Bob, to maintain separation of concerns and enhance maintainability. They detail the use of controllers, use cases, entities, and the importance of not mixing Next.js specific code with business logic. The script also covers authorization checks, data persistence, and the benefits of this structured approach for scalability and team collaboration.
Takeaways
- 📅 The video creator emphasizes the importance of regular content updates to maintain relevance with the YouTube algorithm.
- 🏗️ The discussion centers on the architecture of the creator's Next.js starter kit, drawing inspiration from 'Clean Architecture' by Uncle Bob.
- 🔍 The video explains the concept of layered architecture, including presentation, business, persistence, and database layers, to enhance code maintainability.
- 🛠️ The creator advocates for separating business logic from Next.js specific code, suggesting that this leads to cleaner and more manageable projects.
- 📝 The script introduces the idea of controllers, use cases, entities, and their roles in structuring code to avoid dependencies that complicate maintenance.
- 🔑 The video creator discusses the use of server actions in Next.js as a form of controller and stresses keeping Next.js specific code within these boundaries.
- 🔄 The process of updating group information is used as an example to illustrate the flow from presentation layer to business logic and persistence layer.
- 🛡️ The importance of authorization checks within the business layer is highlighted to ensure that only authorized users can perform certain actions.
- 🗂️ The script touches on the use of data transfer objects (DTOs) to prevent information leakage between layers and maintain a clean architecture.
- 📁 The creator prefers a directory structure that collocates related components and logic to simplify maintenance and onboarding of new developers.
- 🔍 The video ends with a discussion on the benefits of decoupling business logic from presentation, making it easier to refactor or change the application's approach in the future.
Q & A
What is the main concern of the video's author regarding their YouTube channel?
-The author is concerned about maintaining relevance on their YouTube channel by regularly publishing content, as they have not published a video for about a week.
What architectural concept does the author discuss in the video?
-The author discusses 'clean architecture,' a concept from a book by Uncle Bob, which emphasizes structuring code in layers with specific rules to avoid dependencies that can make a project unmaintainable.
What are the four layers mentioned in the layered architecture approach discussed in the video?
-The four layers mentioned are the presentation layer, business layer, persistence layer, and database layer.
Why does the author recommend against making direct database calls in React server components?
-The author believes that making direct database calls in React server components is not a long-term maintainable solution and suggests using a layered architecture for better control and separation of concerns.
What is the role of 'controllers' in the context of the author's discussion on code architecture?
-In the context of the author's discussion, 'controllers' or 'server actions' act as the presentational layer that handles the interaction with the user and invokes business logic without mixing with Next.js specific code.
What does the author mean by 'use cases' in their code architecture?
-In the author's code architecture, 'use cases' refer to the business logic that is invoked by actions and is responsible for processing data and applying business rules, independent of the presentation layer.
How does the author implement authentication and rate limiting in their server actions?
-The author uses a library called Zsa to create middlewares for authentication and rate limiting, ensuring that only authenticated users can perform actions and that endpoints are protected against abuse.
What is the purpose of the 'persistence layer' in the author's architecture?
-The persistence layer is responsible for providing methods to store and query data from the data store, abstracting away the specifics of the database or ORM being used.
Why does the author recommend collocating components and related files in the same directory?
-The author recommends collocating components and related files in the same directory to make the project easier to maintain and understand, as it provides a clear association between related parts of the application.
What is the potential issue with not following a structured architecture like clean architecture or layered architecture?
-Not following a structured architecture can lead to business logic being spread throughout the application, making it difficult to maintain, understand, and refactor, as well as increasing the risk of inconsistent logic across different parts of the application.
Outlines
📅 Consistent Content Publishing for Algorithm Relevance
The speaker begins by addressing the lapse in video publishing on their YouTube channel and the importance of regular content to maintain algorithmic relevance. They introduce the topic of discussing code structure, specifically the architecture of their Next.js starter kit. The speaker invites viewers to engage in a discussion about the merits or drawbacks of their approach, which is inspired by 'clean architecture' principles as outlined in a book by Uncle Bob. Key concepts include controllers, use cases, entities, and structuring code in layers to avoid dependencies that could hinder maintainability. The speaker also contrasts their approach with common practices of directly integrating database calls within React server components, advocating for a more layered and maintainable architecture.
🏛 Implementing Layered Architecture in Next.js Starter Kit
In this paragraph, the speaker delves into the specifics of implementing a layered architecture in their Next.js project. They describe the use of server actions as a presentation layer, emphasizing the importance of keeping Next.js specific code separate from business logic. The speaker illustrates this with an example of an admin modifying the text on an info page, explaining how server actions are used to handle user inputs. They also discuss the use of a library called Zsa for creating middlewares that handle authentication and rate-limiting, ensuring secure and efficient access to authenticated endpoints.
🛠️ Business Layer and Use Cases in Clean Architecture
The speaker continues by explaining the business layer in the context of clean architecture, where business rules and logic are separated from presentation and data persistence concerns. They discuss the use of use cases or interactors to handle specific business requirements, such as updating group information with proper authorization checks. The speaker also touches on the concept of role-based authorization, where different user roles have varying levels of access and capabilities within the application. The paragraph concludes with a brief mention of business entities, which encapsulate business rules but are not deeply explored due to the simplicity required for the starter kit project.
🗃️ Persistence Layer and Data Access in Application Architecture
This paragraph focuses on the persistence layer of the application, which is responsible for interacting with the database to store and retrieve data. The speaker describes methods for updating group information and the use of a repository pattern to abstract database operations. They also highlight the importance of keeping the business layer unaware of the specific database technologies or libraries used, which promotes flexibility and maintainability. The speaker provides a code example using Drizzle ORM to demonstrate how data access is implemented in their project.
📁 Directory Structure and Project Organization
The speaker discusses their approach to project organization and directory structure, advocating for colocation of related files to simplify maintenance and onboarding of new team members. They argue against having a monolithic components folder, preferring to keep components and related server actions within the same directory as the page or route they pertain to. The speaker also addresses the handling of React server components and the potential use of caching to optimize data retrieval. They suggest the possibility of creating a 'loaders' directory for functions that are called multiple times within the application to streamline data fetching and caching.
🔧 Refactoring and Maintainability in Software Architecture
In the final paragraph, the speaker emphasizes the maintainability benefits of keeping the business logic separate from Next.js specific code. They argue that this separation simplifies potential refactoring, such as transitioning from server actions to API endpoints, without affecting the core business logic. The speaker also warns against spreading business logic throughout the application, which can lead to inconsistencies and increased difficulty in future changes. They conclude by inviting viewers to share their coding approaches and engage in a discussion about best practices in Next.js development.
Mindmap
Keywords
💡YouTube algorithm
💡Nextjs starter kit
💡Clean Architecture
💡Controllers
💡Use cases
💡Entities
💡Layered architecture
💡Server actions
💡Zod
💡Persistence layer
💡Collocation
Highlights
Publishing a video regularly is important for maintaining relevance with the YouTube algorithm.
Discusses the structure and architecture of the code for a Next.js starter kit.
Emphasizes the importance of using clean architecture principles in coding projects.
Introduces the concept of layered architecture, including presentation, business, persistence, and database layers.
Recommends avoiding direct database calls in React server components for better long-term maintainability.
Advocates for separating Next.js-specific code from business logic to maintain clean separation of concerns.
Highlights the use of controllers and use cases to manage different layers in the code.
Mentions using Zod for authenticated actions and middleware creation.
Explains the process of validating and parsing input data to ensure it matches the expected structure.
Discusses the role of business logic in authorization checks and role-based access control.
Illustrates the persistence layer's role in handling data storage and queries.
Mentions the repository pattern and personal preferences for code readability.
Stresses the importance of abstracting ORM usage away from business logic.
Describes the benefits of maintaining a common architecture pattern within a development team.
Highlights the use of data transfer objects (DTOs) to prevent leakage of unnecessary data between layers.
Advocates for collocating components and server actions within the same directory for easier project maintenance.
Explains the process of loading data in React server components and the potential use of cache methods.
Emphasizes the maintainability and refactorability of separating Next.js-specific code from business logic.
Highlights the risks of spreading business logic across multiple layers and the importance of centralizing it.
Transcripts
so I think it's been like a week since
I've published a video on my channel and
I figured I should probably get
something published out there before the
YouTube algorithm thinks I'm no longer
relevant so I want to talk about the
structure of my code and how I kind of
architect the code for my nextjs starter
kit um you can kind of take what you
want from this you can in the comments
you can say that this is dumb you can
say hey I agree with what you're doing
maybe we can have a discussion about it
and just learn from it a lot of the
stuff I'm going to be showing in this
video do come from an idea called clean
architecture there's a book called clean
AR chitecture written by Uncle Bob we
apply this or we try to apply this as
best as possible at work so we have
something called like controllers use
cases entities and you kind of structure
your code in different layers and
there's certain rules that you follow so
that you don't have dependencies that
cause your project to be a little bit
more unmaintainable there's also like a
layered architecture approach where you
basically have like a presentation layer
a business layer a persistence layer and
a database layer this is also kind of
what I'm doing on my starter kit which
I'll kind of walk you through the
different layers that I have applied I
highly recommend that you do something
like this on your projects like I've
seen a lot of videos and tutorials where
people are just like doing uh Prisma
calls or drizzle calls or SQL calls
calls directly in their react server
components when the page loads and
although that works I just don't think
it's a very long-term maintainable
solution uh what you want to do is just
apply some type of layered architecture
so that you have more control over like
who can read the data who can manipulate
the data and you can kind of test your
business logic separately from all the
nextjs code okay so let's just draw a
little bit so in my project I'm trying
to do a layered architecture type of
thing right so we have nextjs and to
help kind of exemplify what we're doing
um we are going to follow a use case
where I'm an admin or an owner of this
group and I want an admin or owner to be
able to modify the text on the info page
like over here if I say hello world
I save this I want other users who are
not admins or uh owners to be able to
see this text when they go and view this
group directly so in terms of that use
case what we just did in xjs is what you
probably know is I'm using server action
so let's just go ahead and say we have a
server action I'll make a little box
here I'll say server action and this is
one of the layers I'll call this a
presentational layer you may also call
this a controller uh it does doesn't
really matter the point is you want to
keep all your nextjs specific code to
the left of this line right you don't
want react cach methods or unstable cach
methods bleeding over onto the right
side of the line you don't want
revalidate path or revalidate tag
bleeding over cuz now at this point you
don't have nice clean uh separations
between like what's in charge of the
presenting and the controlling of your
your code and what's in charge of the
actual business logic so that leads me
to my next point is if I consider a
server action kind of like a controller
if you were to look at this layer
architecture the presentational layer
would probably be like react or your
react server components that render out
the page when you invoke an action again
that's kind of calling a presentational
layer uh controller again if you were to
look at the clean architecture Circle
your controllers in your presenters are
all in this interface adapters right so
the user needs to do something they are
going to invoke some type of controller
invoke some type of adapter and in our
case I'm basically going to say that a
server action is a form of a controller
again feel free to call me out in the
comments if anything I'm explaining
doesn't seem right but this is just how
I kind of think about it so when a user
clicks on the save changes that invokes
a server action which again is still in
this nextjs layer over here so let's
kind of look at the code I have a page
and I click on a button and it calls an
action let's try to figure out where
that's happening I have an action here
called update group info action now
something that I'm doing in my codebase
is I want to make sure that everything
that goes in and out of this action is
parsed right I want to make sure that
the stuff that's sent in it matches a
certain type of structure I want to make
sure the group ID sent in is a number
there is an info that's sent in that is
defined and once I get that information
I can kind of trust it and start running
some controller type of code and again
notice that my actions this is where I
keep revalidate path or revalidate tag
or redirect all of the nextjs SL uh
react specific code I would probably
keep it inside of This Server action now
if you're curious how I'm using an
authenticated action I'm using a library
called Zsa which allows you to basically
create middlewares where for example I
have this authenticated action I create
a procedure and anytime I want to create
a action that requires authentication
all I do is I just run some code make
sure that the you know the cookie set
the session is set I also do some rate
limiting just so that all my
authenticated endpoints are just rate
limited by that user ID I don't want
people trying to maliciously abuse my
systems and then I return the user right
so again this is still all in the the
controller presentational layer if we
were to go back to this diagram now at
some point you'll see that after I've
done the parsing of the input which
comes from a form or whatever I'm
calling something called a use case this
is just my nomac claure of like how I
like to denote this stuff and this comes
heavily from the clean architecture book
so all of my actions invoke use cases
and these use cases leads us to the next
point I want to make out and that is the
business uh business layer a business
layer and then inside of this business
layer Theory clean architecture believe
that he calls them use cases or slash
interactors okay let's just look at this
little diagram real quick and you'll see
he calls the little orange red circle
use cases and then that points to
application business rules okay so from
my perspective what is a business rule
what are concerns of the business logic
well the action all it's in charge of is
basically taking in figuring out what
the authentication methods are maybe
you're using JWT Maybe using session
storage doesn't matter the business
layer does not care about that all it
cares about is that you're passing in
the correct data um that it would expect
so in our case this update group info
use case this needs a group ID and an
info and it also takes in an
authenticated user again this thing
doesn't
know if we're using jts or sessions it's
just give me a user object and I'm going
to use that user information to figure
out if a user should have access to
update the group info so what this does
is basically we're going to pass over
some user information the group ID
whatever and we're going to invoke a use
case again that I called um update group
info use case I might as well go back to
this one and change this one to have a
name just call it uh this action here so
this action is going to invoke this
business layer use case interactor and
this is where you want to run some type
of authorization check so in my group
finder application I have a lot of role
base authorization checks in place you
can be an owner or an admin of a group
or you can just be a member of a group
and if you're an owner or an admin an
owner can actually go and delete the
entire group an admin just has the
ability to modify you know some info
they have the ability to come in here
and maybe promote other users to an
admin or demote users Etc but the owner
has you know very special privileges
that you have to encode this in business
logic somewhere and so how this works is
basically this use case is where you're
going to run your you know authorization
checks is this user an
owner or an
admin and then if they are you want to
be able to allow them to update this
information so let's look at the code
because it's actually super super simple
so basically we first we fetch the group
by group ID if there is no group I throw
an error and again you should not be
throwing any type of nextjs specific
erors here you should not be calling
redirects or anything keep it simple
throw errors or return some type of like
error objects if you need to and then
finally I do another check that says if
I'm not the group
owner go ahead and throw an error that
has unauthorized and then finally if
everything passes we just go ahead and
update that group info using that info
that was passed in now
technically there is more to clean
architecture if you look at this uh
diagram there's something called
entities and I'm a voiding entities just
to keep it simple for my you know oneman
Team starter kit project but at some
point you may want to encode business
rules to say info can only be 1,000
characters right that is business rules
that the business people can Define and
I know when I say business like I'm just
talking about myself because this is
like a oneman project but when you work
on a bigger team like there's people who
are going to Define how large how much
data some of the stuff can be what is
the shape of this data is it a first
name does it need to be all capitalized
does it need to be proper case stuff
like that and so sometimes what you want
to do is you want to
encode this information in something
called business entities and those
entities can have validation rules
themselves okay now I'm not going to
dive into that because again I'm not
doing that so basically I just call a
method called update group and this is
something called a persistence method so
this is going to lead us to the next
section of our
code which is the
persistence layer okay let's look at the
layered architecture we are over here we
just talked about the business layer a
little bit now we're at the persistence
layer and the persistence layer's goal
is to basically give you methods that
you can invoke for storing and quering
data from your data store whether that
be in postgress whatever so we
have a method over here called update
group so I'll just go ahead and make a
little box here that's going to call
update group going to pass in some
information such as a group ID some info
and there's different ways you can do
this a lot of people use something
called like a repository pattern where
they'll have like an object called I
don't know groups and they'll say update
and they'll pass it whatever information
something like this I think is just not
as friendly to read versus something
update group that's just a personal
preference it doesn't really matter but
the point is is that this layer is
responsible for knowing how to write to
your database which in case I'm using
drizzle but something I want to point
out is that you don't even know I'm
using drizzle right the business layer
has no concept of what omm you're using
what libraries you're using to actually
persist the data all it knows is that I
need to call some method to save this
group information okay that's been
abstracted away about how that actually
happen so let's dive into this code real
quick and you'll see over here I have a
data access folder with like all of my
tables I basically have like a one to
one mapping of a file maps to a table in
my SQL database you can structure this
however you want but the way I typically
do this is I have a groups file and this
has an update group function which
allows you to basically take any group
ID and just update any parts of it right
and so now you start seeing some code
that might look familiar to you which is
drizzle orm so if you go up to the top
here you'll see that I am just defining
like a drizzle orm connection and in
fact let me uh how do I go to the
definition here I think just scroll up
you'll see I'm import reporting this
from DB which is bringing us some
drizzle orm stuff okay so this
persistence method this persistence
layer knows about how to write and
persist the data which if you look at a
layered architecture now we're hitting
the database layer something that we're
using a library we're using knows how to
write data let's just go ahead and put
another line here and this is going to
write directly to a database just draw a
database symbol here here we go I'll
just say post CR cuz that's what I'm
using so if we zoom out a little bit
this is the pattern that I try to follow
in my applications this is just the way
I've been brought up when learning how
to code people smarter than me have
taught me this pattern I believe them
and I follow the pattern too not blindly
but I do try to follow it because I
personally think it is useful and some
of the reasons why I think following
either clean architecture or layered
architecture or some type of pattern is
a everyone on the team has a common
pattern they can follow if you're
working on a project by yourself I mean
you could just raw dog SQL right in your
react server components if you want to I
probably would not recommend that
because if your project actually takes
off and grows you're going to want to
bring in other engineers and you want a
Common Language such as an architecture
that you can all discuss things about
now some teams and projects like to make
this even more complex which I'm on the
fence of a lot of teams will in between
these two layers they'll do something
called data transfer objects DT's to
make sure that that certain things Never
Bleed over so what I mean by bleeding
over so for example in the business
layer let's say you're fetching
something from a persistence layer an
update group happens to update the group
but then return the whole group object
back you could potentially have a bunch
of extra fields on this database that
you haven't actually like cleaned up you
could have like a group name a group
display name all this other stuff and
you may not want that to ever bleed over
into your business layer right so
sometimes what you do is you'll create a
data transfer object so that all the
data is basically sent through a mapper
to make sure that you only return the
things that are necessary from your
persistence layer back to your business
layer and again you want to make sure
that you only return certain things from
your business layer back to your
controller or back into your react
server component so that you don't leak
sensitive information or information
that's not a concern of any of these
layers one good example I've seen is a
lot of people who use
mongodb a lot of the times the unique
identifier for your IDs is underscore ID
and they'll start bleeding that over
into every single layer and you can
actually look at the network request and
see oh all the entities have an
underscore ID on them I'm going to
assume you guys are using mongodb right
because that wasn't really abstracted
way too well and using something like a
dto could potentially help prevent
leaking information about your you know
your underlying architecture of your
system maybe you don't want people to
know you're using mongus because that
opens up more security attack vectors of
how they can abuse your system stuff
like that so that's kind of how I would
recommend at least Loosely following a
project the only dto stuff I end up
doing is with these actions over here I
can actually put an output as well and I
can specify what the output needs to
look like so over here I can say well I
just want this to return uh nothing I
could say void of undefined or something
and that at least gives me a little bit
of certainty because Zod is going to
verify that whatever I'm returning here
it has to match undefined if I were to
accidentally take the group that was
being returned here and let's just say
like name is Bomb notice that I get some
typescript errors that says hey you're
returning some information where you're
not supposed to be returning that
because you specified an output of
undefined something like that can be
very useful and again this is basically
a dto it's just that we're using
libraries that just automatically do it
for us and I don't want to waste a bunch
of time writing the mapping code and
writing the you know the dto objects
with classes and stuff like that now
before I wrap up this video I do want to
kind of touch a little bit about the
directory structure of my projects I try
to collocate as much as possible so if
I'm looking at a page right here for
example I'm on my group info page
everything that's on this page should be
in the same directory as my info route I
don't like having a separate components
folder where I put all those and then I
import them I want all my components
that are related cooc in this directory
because I think it makes the project a
little easier to maintain at work we do
an approach where we have like every
folder holds different things and those
things are separated by type and you end
up having this folder that has 500
different files in them and there's like
no good way to really understand like
what is using this thing okay so if it's
not an actual res sharable reusable
thing then I would just co-locate it for
example typically server actions have
stuff like this like revalidate path
which means they are very tightly
coupled to the page or the route that
you're on so it makes sense to just put
your actions directly in this folder
also with components this is the only
place in this entire application I have
a component that looks like this so I'm
not going to go and find my components
directory and put it in there I'm going
to collocate it so that if I were to
onboard someone under this project they
can also have a common Convention of
like okay I'm looking at the info page I
have 95% certainty that every component
that's needed for this info panel is
probably going to be right in this
directory now another thing I'm still
trying to figure out how I want to
approach this is basically the react
server components when you hit a page
you typically need to load some data and
so the way I've been doing this is I'll
just call these use cases directly here
uh before I call the use case I will
basically get the current user from a
session and then I'll call the use case
and pass it the current session and then
also I'll pass it the um whatever
arguments I might need and that'll
return some data for me right and I can
kind of throw errors inside the react
server component where I could actually
have like an errors. TS file handle that
and display something else uh the kind
of exemplify what I mean so this is the
info page it takes in a group ID which
is loaded from the URL
here and I basically take that and I
call a git Group by ID use case let's
just go ahead and go through the whole
flow real quick quick so you understand
uh I call this git Group by ID use case
in our case I probably should do some
type of authorization here to make sure
that there's no like sensitive data
being leaked but um again you can kind
of search for a lot of these groups
publicly and that ends up calling a get
group by ID method which calls a drizzle
method to get the first group by an ID
okay and I don't see any issues with
doing this as long as you just you know
make sure you're passing in the user
sessions again because you're calling
the user case during your react server
component and all the business logic is
kind of encapsulated there now something
that I might at some point end up
needing is when you have a complex tree
and you have to call the same method
multiple times and your react server
components typically what you want to do
is you want to call a cache method which
is built into next I'm sorry this is
built into react actually um so you can
bring in a cache method from react and
you can wrap your functions with this
cach uh Factory function
basically so that as it's traversing
your react server components if it finds
the same method it's just going to use
the cach results for that individual
request that your user made and then on
the next request if a new user comes in
it hits the same page brand new cache
it's not going to reuse the old stuff
okay so in some cases you may want to do
that and I might actually add a new
folder here or a new file called loaders
and then I would probably just make a
new fun function here called like uh get
group by ID
loader and then you could basically um
you want to do this I could just set
this to
Cache like this and then I could just
have this taken a group
ID like so and then you know call the
use case in here goad and say return get
group by ID use case something like that
and then also in the loader you could
potentially get the user so get current
user like this
so that I can pass it in and then
obviously we want this to be an
asynchronous function so we do this if
for some reason you do end up needing to
like wrap stuff with the nextjs like try
to avoid going into your use cases your
business layer and like trying to add
cache methods here because again you're
breaking that Convention of like now
you're running a react code inside your
business
layer okay so technically if I were to
do that refactoring I could just call
that loader here and then I can get that
information information and use it so I
want to talk on one last Point as to why
I think this is more maintainable and
the reason is if you keep all your
nextjs code out of your business layer
what you can do is if down the road you
decide that you know what server actions
isn't it server actions is just not
worth doing it's causing more headache I
rather go back to use form Hooks and go
back to uh react query and just hit API
in points well the refactoring involv D
with doing that is very simple cuz now
you have this method that it doesn't
care about anything in nextjs it doesn't
care about how you're doing you know how
you're handling your your actions or
your post requests or mutations it just
needs some input and so if later on you
decide you know what I actually want to
make this an API inpoint well it's super
easy to just you know have a new API
inpoint
directory and invoke this which makes it
very convenient and a lot more
maintainable another thing that I've
seen in some projects is if you don't do
some type of approach like this you end
up taking your business layer like your
your your logic that defines like when a
user should read something and you end
up putting it everywhere like you'll
take this you know there's some certain
rules that you need to check to see if a
user has access to get a group and
you're like oh I'll put it in this react
server component and then later on
you'll decide that you need that same
logic and you'll put it in another place
maybe you also need in front of the API
but then you have all this business
logic that's kind of sprinkled out
throughout your controller and your
presentational layer which you'll start
updating in one place and you'll forget
to update it somewhere else and then
it's just a big headache because you've
basically spread out all of your really
your core logic throughout your entire
application it becomes very very hard to
maintain and understand and also to even
switch off of in the future if you
needed to for some reason um anyway I've
been rambling for a while now so I hope
you guys enjoyed watching this video
again I just wanted to get something out
there for you all and hopefully this
elevates your knowledge in coding a
little bit again leave a comment if
there's a different approach you like to
make your applications if you're using
nextjs with server actions let me know
we can have a discussion about it other
than that have a good day happy quing
関連動画をさらに表示
Clean Architectures in Python - presented by Leonardo Giordani
Top 5 Most Used Architecture Patterns
System Design and Architecture for Product Managers : Tech Every Product Manager Must Know !
React's most dangerous feature
"Clean Code" is bad. What makes code "maintainable"? part 1 of n
The Power of Scriptable Objects as Middle-Men
5.0 / 5 (0 votes)