Transcript
This transcript was autogenerated. To make changes, submit a PR.
Hi there, I'm Joshua Arvin Lat and I'm going
to talk about pragmatic state management in react,
angular and UGS applications.
So in this session we will share
some practical tips and techniques that I've learned over these past couple of
years when dealing with these libraries and frameworks.
So so before we start, I'm going to introducing myself.
I am Joshua Arvin Lat. I am the chief technology officer
of Nuworks Interactive Labs. We build a lot of websites,
we build a lot of applications, and I'm going to use
some of the things that we've learned there along with some of the things that
I've learned in my previous companies. Also these we use all of these libraries
and frameworks to build basic to more
complex websites and applications. I'm also an AWS
machine learning hero and I'm the author of the book Machine
Learning with Amazon Sagemaker Cookbook.
So if you would like to take a look at my book,
you'll probably find there things that you need in order to get
your machine learning applications working in the cloud.
So yeah, feel free to check it out. However, for today
we're going to talk about web application development with react,
Vuejs and angular and all the other state management
libraries. So let's start so
let's say that we were given a
project, a project that involves let's say about
four developers, maybe one product managing one
QA and then one DevOps person,
and we are supposed to build an e commerce application.
So after about maybe one to two months of planning,
your team has decided CTO use these certain tech stack.
And then after a bit of research also you have decided
to use a state management library to
further improve the overall organization and architecture
of your application.
So in the first couple of weeks,
the team is super excited trying out these new tools because almost
everyone has never used the shiny new tools,
especially the state management libraries. But of course,
you did some research before you got started and you did tell
everyone that yeah, after reading some blog posts,
a lot of people did get successful using
the state management libraries.
However, after two months using
these different tools and libraries, you've realized
that things are not working out and
you initially thought that the project would be easier using these tools.
However, the tools seem to
be making things much harder than it's supposed to be and
there's no going back because the tool is being used in different
parts of your application. And if you were to refactor things
again and remove the usage of these certain libraries and tools,
these, it might add an additional, let's say one
month CTo, two months just to get it back to a stable state.
So this is probably how your team looks
like after it has encountered a lot of blockers,
especially if the tool is not helping you. And instead
it's, yeah, like I said earlier, giving you a much harder time to
get things rolling.
So the question here is, and this is a really tricky
question to answer, is when do we use an additional
state management library? And before we answer that,
let's ask ourselves what a state management library and
what is state? So when you're dealing with applications,
the UI, the thing that you see would always be
rendered there and it's a function of
the data in the state. So if, let's say that this is
your value and then this is going to be your UI. So if
your value changes, then the UI should update as well.
As we have more components in our site, the usual
challenge here is how do we make these components communicate
with each other? How do we manage state? And even when we're
already using react, view and angular, we do feel
that after the code gets a bit messier and data
is being passed through the different props and different things,
we start to think about is there a better way to do this?
And a lot of us would say, yeah, maybe let's use
a state management library.
So here are some of the options available, and of course this is not an
exhaustive list, there are so many options out there.
But let's say you have NGRX, you have MoBX, you have redux,
recoil, viewx and more. And the
question here now is when do we use an additional state management libraries
to support our needs when using the libraries
and frameworks that we have. So the
next couple of minutes would be focused
on answering that. But let's start first with
this simple examples.
So if we have a very simple application,
these, we have one parent component and then we
have two child components where these child component
needs to do some
sort of action or modification on
child number two on a sibling.
So one way to do it is for
child one to communicate CTO parent to its parents
and then finding a way for the parent to
send that message to child number two.
So this seems pretty straightforward and we can technically survive
without using any sort of additional state management layer.
And this is usually one of these easier examples there
because yeah, the code will not
be as complex and it's also something that's
readable and easy to debug. So if there's something wrong with, let's say,
child number one, and we need to fix it. It's easy to find everything that's
connected to child number one.
However, once things get a bit more complicated,
and especially if our needs would involve, let's say,
having a grandchild, let's say, as seen in this image here,
one of the grandchildren of child one needs to
talk to one of the grandchildren of child two. So if
we need to cases that message or pass
that event to the other
grandchild, which is not directly accessible
from the first grandchild, then we have to do some sort of prop drilling
mechanism where grandchild passes its
data to child one, goes to the parent, goes to child two,
and then goes CTO the grandchild. And yeah, you're probably
aware that the more levels we have here, and the more things
that's happening internally, the more complex the
code becomes. And instead of us being able to make the most
out of this concept of being able to
identify which things are interconnected
or related to each other, it's using to look like some
sort of a spaghetti code, especially if some of the grandchildren will not
really make use of the data which the other grandchildren would
need. And there are different ways to solve this. And one of the
major issues that teams encounter
is that these immediately jump into solutions.
Especially when they encounter this prop drilling scenario,
they automatically decide
to use a state management library. And that's
a wrong thing to do. Why? Because you can
technically solve this with other solutions,
which we'll see later.
So what's our overall objective anyway? If we were to
take a step back? Our goal is to be able
to manage this mess. And whenever the
team is growing, whenever we have to deal with a
code base that has its size increasing
every single day, and the separation of
code and the functions and the
different things that's happening inside start to get more
blurry, then we need some way to organize things a bit,
so that when we need to look for something, it's easy to find where
to fix the problem.
And one of the things that people are talking about
when using state managing libraries is that in
most cases, you're going to deal with a lot of boilerplate code.
And in the beginning, when you're talking about 20 lines of code,
without those additional state management libraries, people complain that,
yeah, those 20 lines will become 20
lines plus ten, plus ten, plus ten, total of 50 lines.
And that's just one example of this. And even for
the simple things, we need to add a lot of boilerplate
code, which already affects people,
because they're going to put and add a lot of files,
they're going to add a lot of code, which may not make sense, especially at
the start when the project is still small.
Of course, when the project gets bigger, you'll start to realize, okay,
maybe that makes sense, but this really depends on the project.
This really depends on the type of state that you're dealing with,
and there are a lot of factors we need to consider.
So if we were to understand what's really happening here, it's like
if we're just dealing with a really small application, let's say on
the left side, we have a refrigerator and
we need to manage and
organize things a bit where to put the vegetables,
the fruits and everything inside the refrigerator.
If we try to over engineer things a bit accidentally,
we may end up having this sort of container system
where most of these would be empty space and we would have more
boilerplate code than the actual relevant code
itself, which is a bad thing. And the goal here is for us
to understand when's the best time to
use these layers to keep things
organized. So the
first thing we need to do is to try solving this by
making the most out of what we have first. What do
we mean by that? Let's try not installing additional
libraries first, because in most cases you
will be surprised that these libraries and frameworks may be more
than enough to get things done.
I'll repeat again, in most cases we'll most
likely be able to get this done with these libraries and frameworks.
So view angular and react even
without installing, let's say recoil, redux,
Mobex,
NgrX, rxgs and so on,
we'll be able to manage things a bit. Because sometimes
people think, okay, we need to manage redox,
when in fact these libraries and frameworks already have its own internal
mechanisms to get things organized and
dynamic. So here are
some of the things that you can use. And let's say
that if you were to use use context and use effect and use ref and
use state with react, you'll be able
to take on the basic to medium sized projects
even without using redux or other state management
libraries with angular. Given that you're
dealing here with a framework with a lot of things already installed
there and ready for you to use, you can use a shared service
instead of NgRX first. Maybe a shared service
where different components are able to talk to that shared service
would do the trick, especially for projects that are
being converted which are getting a bit more complex but still considered
medium sized. And then yeah, with a bit
of dependency injection. Also, you can combine
that with the different strategies inside angular to
keep things organized in your angular app and then
for view js. Maybe you can start first with
the mentals, the foundational building
blocks of Vuejs, and then yeah, try to implement also some
other techniques like using a simple global store and maybe
a global event bus and understanding how
these things work, you would be able to
organize things better. And it does not
involve a lot of boilerplate code, especially yeah,
in the similar examples earlier where you're just
dealing with basic to medium sized applications.
There are other techniques which I will not share here,
so feel free to take a look because the goal here is to
be able to maximize the tools first before
introducing new ones. Because the moment you introduce new
tools in your arsenal and in your project,
all developers of that project involved in
that project needed to learn these new tools as well.
So the familiarity level takes
time. Being able to be more familiar with these tools
take time and as much as possible, try to limit
the tools, especially when the other tools are not yet needed.
So here we can see that if we were to use react
and redux, when the
project is somewhat smaller at the
start, you will start to feel that, yeah, there's a
lot of boilerplate code and the relevant logic code is just a piece
of it. So you'll probably feel when it's
best to use redox. And one of the
technique that can be used here would be to use, let's say something like redux
toolkit to reduce the boilerplate code. So do some
research first before taking things on, because there might be newer
solutions as we go along when you're using certain
tools and frameworks, because that's one of the known weaknesses
of using this state management libraries.
What if, let's say we use Mobex to
replace Redux? So for one thing,
people think that redux and react are
the partners when it cases to state management in react. However,
that part is interchangeable and we can use other state management
libraries with react. So for Mobex, for example,
there's more magic when using Mobex.
And of course the assumptions are a bit different here because the way it works
is super, is kind of different as with redux.
So there's definitely less boilerplate code. And when your team
size is maybe somewhat smaller than
what you have compared to when you're dealing with Redux,
then maybe Mobix is for you. But of course there's more magic,
things are less explicit and so on. So you have to understand
the concepts here as the assumptions are different,
like what I mentioned earlier.
So now, one of the
things which would make it easier for you to choose would be time,
because time will affect everything,
it will affect the budget, it will affect
the launch dates, it will affect the things
that you can do. And this will affect also
the debugging time that you have. So what do I mean by
that? When you have a more complex
setup, it will take more time to build
it. If you have more developers in your team,
you need to manage everyone's time. So if you
have a 30 man team versus a five man team,
it's important to be able to manage complexity while reducing the
overall time to deploy things, because it's super expensive when
you're dealing with a much larger team compared to a smaller one. So if
you have a smaller one and the timeline is a bit tough
and you need to deploy things, let's say, next month,
then doing something the elegant way may not
be the right way to do things. Maybe try to do something that's somewhere there
in the middle. That's why you need to be able to
research first what options are available for you and what are the
constraints that you have. So let's say that you're using view js
already in your project, and if you want to migrate it to react,
you need to take note of the skill level of your developers,
also the amount of time it takes to migrate your project from view to react,
and so on. And if you want to use, let's say,
recoil and everyone else has used redux, then you have
to also take into account the time it takes for people to learn recoil
and these amount of time that you need to standardize
things. Because even if you have this state management library, it will not automatically
make your code cleaner. You need to be able to use those libraries
properly before you can get a polished application.
Another question we have to ask ourselves. Do we want more
magic or do we want less magic? Let's say when
you're using Mobix, a lot of magic is being done
because of mobex, right? And in some cases,
when we're using redux, things are more explicit.
So when there's a problem, of course it's much easier
to see where the but probably is,
right. And when you have more members in the team, there are less assumptions
to make and you can just see, okay,
there's a problem with this function, or I can just probably
look in these certain files, certain set of files,
and just modify and tweak things a bit there to fix the
problem when you're using more magic, of course, when there
are issues and bugs. And when you're checking things on why it's not working,
sometimes it's harder to debug and troubleshoot. So being
aware of how to troubleshoot these issues is
very important. And knowing the differences between the one day
data binding concepts and two way data binding is crucial.
Also, along with the usage of different tools,
let's say the browser plugins, you need to be able to research
what's available out there. And let's say there's a time
travel mechanism these how can you use it
to debug what's happening inside here?
It's important for us to note that strong assumptions yield
strong guarantees. So if we're using
this certain concept, let's say immutability,
if we're going to enforce certain architecture
patterns in our application, then there's
going to be a trade off. We're using to, let's say,
have more code and more files. But when there
are issues already, in some cases
the issues are prevented and much more
manageable. And those are some of the stronger guarantees
which are results from having strong
assumptions or strong rules. So when you're dealing with
super complex applications, of course you needed to
have this stronger rules,
stronger set of rules to make things more manageable. And of course, if your
application is much smaller and you
are okay to have a higher level of risk,
because you know that this project will probably not evolving
into something larger in the future, then maybe use something that
has more magic in it.
Another thing to check would
be the capability and experience of your entire team.
Whenever there's a meeting. The usual problem these
is that people think that they are masters
of a certain tech stack. Let's say that they have used angular and
NGRX to create a hello world application.
So they create a button and
then use this, it emits something and then something subscribe
or something like that and it works,
right? And these, they add another button and then another component
changes. Because of that,
they assume that they're already experts using angular and
NGRX. However, when we start using
and installing different things there,
let's say that there's an API and then
there are a lot of events happening all over the place,
then that's these. You'll see that there's some sort of gap when
it comes to capability and experience because your team
is unable to resolve something, which is supposedly very easy
when you're just using plain, angular or plain,
let's say even jquery, right? So if you're trying
to complexity things a bit,
using a new layer then
maybe it's time to step back a bit and check, do we really
need these tools? And if you need these tools, do we need CTO?
Make sure that we're trained first and capable
of solving more complex problems so that
things won't be implemented the wrong way.
So there. So the goal here is for the team to
make less mistakes or no mistakes, so that they'll
be able to use the tools properly.
One way to do this is to give an exam to your
team members so that it's very easy to see
if they're really capable of building a medium sized complex applications
with these tech stacks, because it's easy to say, yeah, I can build
something like that. But if you were to do things hands on,
and if you're going to build a clone
of what you're supposed to do, something that's more isolated and
something that's easier to perform in, let's say 8 hours,
then that would be your way
to identify if your project is going to succeed with this text
using this certain roster.
In addition to this, it's important for us to identify and note the
different types of state and why do we need to know these things.
For one thing, there's a tendency of team members to put everything
in the store using the state management libraries,
and in most cases that's going to be overkill. There are only
certain types of state that we need to put in the store,
and it's not just that. We also need to know
the different ways to control the state and to know
where to store the state. Also, for example, in server state that's
stored in the server, you will not need
the more advanced and complex solutions
there, especially if the operations are pretty straightforward. Let's say that
you have a form and you just need to submit the form. Does it
need to go through all this complex code just to send
a post request to the server?
And maybe you can store also the state in the router and
so on. So being able to identify the different types of state would
help us identify which state can
be stored inside in
the store of the state management libraries, for example, local UI state, you don't
really need that stored in the global state then yeah,
it's better if it's just there in the
scope of that component.
So why do we have an image of
a hammer here? Because if all you have is a hammer,
everything becomes a nail. And if you try to use
these certain tools and text tags in all of your applications, you'll start to
realize it's not going to work for all of it. If you try to
read a blog post saying yeah, it works for us, this certain
tooling works for us in our project, and you start
copying their text app without thinking about the
implications and how it would really work in your own context
and application, then yeah, you'll encounter
a lot of problems there. So the first step here
is to check what's out there and what's
available and try to select which tools
are most suitable for your context for your own application.
So for example, for project one and
it's already using Vuejs, then yeah, just use vuejs.
If it's not going to evolve into something that's super large,
then Vuejs would do the trick. And maybe there's no need to
use vuejs there. For project number two,
you're using Vuejs there and you start to realize actually
the code is getting much, much bigger. The team
needs to use view x then yeah, these use viewx for that and
make sure that Viewx is used properly and you're
just using viewx for the state that is
supposedly in, that is supposed to be in viewx
because you can use both view the view way of things
and the viewx way of things when dealing with state in an application.
There's no need to be pure when choosing these
types of things because whatever works for your team should
do the trick. For project number three,
let's say that your team is using react and
then your team decides to use recoil instead of redux,
then go for it. Just make sure that you don't change your
minds midway and decide to use redux so that
you have to refactor everything and start again
from scratch just to realize let's use redux or
mobile instead. And for project number four,
maybe you decided to use angular for that. Or the client may
be already be using angular for it, and then you're supposed to
build on top of the existing framework then yeah,
use angular. If you think that it makes sense to use NGRx or
other options, then yeah, test things, but first
and identify how it would affect the timeline and
how it would affect the happiness of these developers and also their productivity.
So this is one good example on how to take a look at it.
People think that oh yeah, these moment the project becomes a
bit complex, maybe somewhere around medium complexity. That's the
time I need to start using the state management libraries.
But like I said, in most cases you may not need it.
The best way to do it is to start checking all of the
features and functionalities of the
library or framework that you're using. For example, angular. It has
services there. By using, let's say, the angular CLI, you'll be able
to get a service. And these, you can just have the different
components talk to each other using a service as one example.
But once things get a bit more complex and you start to realize that you
need to manage how the data is being managed
and how the data flows. Cto the different components these, yeah,
feel free to introducing NGRX, especially on a certain
complexity level where you have a single page application and a lot of components
are interconnected.
Other considerations we needed to take note of would be managing the performance
issues, because when you're using state management libraries,
it's easy to get things started when you're doing a hello world project.
But when you're dealing with a real project, you will realize
that some parts of your application will be slow. So when you're,
let's say, rendering a certain page, you do not want
to accidentally trigger certain parts of your application,
and then there's a chain reaction, and then this certain component, for some
reason loads really slow, or sometimes
it flickers. We also need to deal with memory
leaks, especially when you're dealing with components and you
need to do some cleanup. It needs to be implemented
properly using the library or framework of choice.
We also need to take note of how to reduce the boilerplate
code, and there are ways to do that, especially in my example earlier where we
use redux toolkit to reduce the overall boilerplate
code to speed things up a bit. Also, and also CTO.
Add more CTo be more straightforward in terms
of like, instead of choosing
something over the other. Sometimes having a more rigid
set of timelines would do the trick.
And then also we need to identify antipatterns when using
these differences, libraries and frameworks, because these antipatterns would be
different, because these libraries and frameworks
have their own ways of doing things.
Finally, why do we have a picture
of a playground here? Don't use your real projects
as a playground. Create a small pet project,
or maybe create your own personal website or something like that, and use that
as your pet project where you would try out these tools.
Do not experiment on the actual projects
because you do not have any room for mistakes or
failures there. You are not supposed to learn
and apply things at the same time and expect
things to be clean when
it comes to implementation. As much as possible,
you would do your learning in
a different environment where you can write messy code
without having to worry about the implications because once you need
to implement things in a real project, it needed to be
clean, and you need to worry about the constraints like the timeline, the budget,
and the people that you work with. You do not want to introduce a new
tool to a project where all the other developers in your
team have no idea what you're going to introducing. So again,
in summary, do not use your real projects
as pet projects where you will introducing fancy
new tools just to add to your resume.
And that's pretty much it. Thank you again for
listening to my my talk and hope you learned something new. And again,
I am Joshua Arvin Lat. You've learned a few things about
pragmatic state management in react,
angular and UGS application.
Thank you again and have a productive day ahead.