Transcript
This transcript was autogenerated. To make changes, submit a PR.
Jamaica real
time feedback into the behavior of your distributed systems and
observing changes exceptions. Errors in real
time allows you to not only experiment with confidence,
but respond instantly to get things working again.
Close everyone.
Welcome to the stock. We are going to be talking about promises and
some functional programming alternatives for asynchronous operations
like task taskeither, remove data or futures.
But first, let me introduce myself. My name is Natalie
Rocha. I am from Kito, Ecuador. I am a software developer at
stack builders, and I also like to play the
guitar a lot, and we run a
business here for planning social events.
Yeah, that's something you can know about myself.
But let's dig into what asynchronous computations
or operations are. Right?
As you know, JavaScript is by default a synchronous
language. Let's say it's single threaded. All right?
So this means that instructions can run one after the other
and not in parallel. So if we
want to interact with external data, like reading files,
or fetching data from third party APIs,
or executing time operations, when the
interpreter reaches these sort of tasks,
it actually blocks everything else that
can be executed until that operation is
fetched or returned, or succeeds or
fails. Right? These are called synchronous
operations. So to solve this issue, for blocking
that thread, we can use asynchronous code,
right? Think of it as code that can
start now, that you can ask for something and
JavaScript interpreter can solve
it later, right? So when Javascript is running
asynchronously, instructions are not necessarily executed
one after the other as synchronous
operations, right? Some of
the examples of how to handle or create asynchronous code
can be callbacks, promises, or a simple
weight. We are going to be centering ourselves
in promises. Here we have some of the main characteristics
of promises. And first of all,
promises solve the callback hell, right?
So callbacks are just functions that
are passed into other functions. So for example, if you wanted
to resolve an asynchronous operation,
one after the other, you had to call one
function. Then inside that function you call another function and then another
one. So as you can see in this graphic,
this is what you ended up with,
right? Promises are declarative,
which means that we write code that describes what
we want the computation to do instead
of telling it the flow or exactly adding
the steps that we want the
computer to run, right? So it's
a more functional approach. After that,
it has control flow, which means that we can tell when an operation
succeeds, do this, or when it fails. We can error
handle in another way. So it has
control flow when we are computing right.
Another thing is that it has railway oriented programming.
So this means that we basically have a couple of rails.
The left one can be the error rail and
the right one can be the succeed rail. Okay?
So when any kind of computation is in the succeed
rail, it can actually jump into the other one.
It changes the rails to go into the failed rail
because that promise failed. That is
sort of how it works. And they
are also fun to programming, so they
are really simple to think about it, they are really simple
to get it running. As soon as you start
programming, you can make a fetch to an API can,
whatever, catch whatever else. So yeah,
the promises are really great,
but as good as promises are,
there are some things that can be better and some others that
we might forget to handle or things
that kind of happen without the
developer knows. So that can cause
errors in our applications, for example,
egate evaluation, error types and checkered
exceptions and others. We're going to be checking more of this in
the demo. Right, but first let me explain a little bit about
functional programming, just in case you don't have much
concept of it or how does it works.
I'm going to be explaining just a
little bit of what it is, because it can
be a little bit hard to get into it at first because it is actually
more like a mindset. You have to start thinking in
a functional way. But just to give you some
idea of what it is, let's explain it a little bit,
right? I mean, functional programming, as I said before, is a
mindset, but technically is
a programming paradigm, right? So is
the process of building software by composing functions,
avoiding shared states, mutable data and side effects.
Okay, another characteristics and principles of functional programming
are, for example, that it is declarative. So again,
we have to tell the computer what we want and
not necessarily add every specific instructions,
like in imperative programming, of how we want
the program to be running, right? So it's more
like when you define a mathematical function,
you create a function to describe what you
want the result to be. Some other
principles are the immutability.
It specifies that basically you cannot transform
things. Like for example, you define a variable
to be zero, then in other part of the program you decide
that that one is going to be one. Then that is going to be transformed
into arrive, then into a string, because those are things that
we can actually do in JavaScript. But in functional programming,
immutability has to be present.
We also have pure functions, which means that if we define
a function that sums one value plus the
other. The result is going to be exactly the same every time
we sum that value plus the
other. Those are pure functions.
Also, functions are first class citizens that we can pass.
Functions are as parameters to other functions
or higher order functions. So these are concepts
that are present in functional programming. You can dig a
little bit on it, but it's a really cool paradigm.
And Javascript is a multi paradigm language,
so we can apply it to it.
Awesome. Now that we sort of know what functional programming is,
if you didn't, here are some functional alternatives
to promises. We have tasks, task eater.
These couple of options come from the FPTs
library, functional programming typescript.
It's a really cool library that has many
modules that can help you program in a very functional
way. Your code. We also have futures.
They come from the library. Flutter that we are
going to be checking remote data also comes from FPTs.
And we also have this alternative that is effects
that we are going to be talking about a little bit later in the demo.
Cool. So let's jump into the demo to check the functional
alternatives to promises.
Okay, so for the demo, I have created several examples
that explain the alternatives and the difference
with the promises. So let's start with lateness.
For this example, we are going to be using FPTS
task. So what is a task?
A task is basically a promise that can never fail,
which means that it doesn't need like error handling or
stop, because it's always going to be resolved
and succeed. So why
to use a task? I think the main benefit
or the main concept of a
task is that it is lazy. Lazy means
that the task is going to be run only when
it is needed to be run. Like when
we call it or when we, I don't know, we use a use effect
or stuff like that. But they are always lazy. We can create them
anywhere in our code. We can define that promise
anywhere in the code and it is never going to be called it
unless we do it. And that is the main
difference with a promise. Right? Why?
Let's check this code here. If we define catch
that returns a promise that can be resolved and we can
get the data from that promise if we call
it like this, even though we are supposedly saving
it into a constant, this promise is going to be
called as soon as we load
the application. Let's check it. So here, I don't
have it called. If I save this, as you can see,
it is called as soon as we load the application.
Why this happens like that? This is
because the promises have eager evaluation which
is exactly the opposite to lazy evaluation.
Eager evaluation means that whatever thing you create is executed
or run it as soon as it is created.
That's one of the first main difference between
a promise and a task. So here we can
check a little bit on how a task is
defined. As you
can see, it has exactly the same code
as the promise that we have up here.
Well, the only difference is basically the repository or the
GitHub user that we are calling. Right?
And here we do the same like then,
and we get the data. We can also do this,
but I will explain that later.
So as you can see, there is not much difference. The main
difference is this part, which is exactly what
makes a task lazy. If we remove this should
be like that. As you can see, the type fails
because a task cannot be running
immediately as a promise. So here it's going to say it cannot be a promise.
So the concept is exactly that a task
is a promise that is lazy and can never fail.
Okay, awesome. So if
I want to call the task, you can do it with no problem
and you can map it,
you can get the data as exactly the same as a promise.
But the benefit is that it's not going to be called
immediately. So we can call it in a use effect. Or in
this case, I just created this small function that is going to be runted
with this button here. So if I run the task,
the task is going to be called only when I decide to
call it. Okay, awesome. That's the first
example. Let's move to.
I would like to show you composable.
Composable means that we can combine functions,
simple functions, to create a more complicated one,
or function that can resolve something
or care, transform some data that we have into
something that we actually needed.
So for this case, let's check the
difference between composing if it's possible,
in a promise, and a task.
So first of all, as we said before,
promises have bigger evaluation. So as soon
as I call this promise here,
I can't actually compose the
functions, or I can't actually use
the data, or I can actually use the data before
this has been retrieved. So here, let's check.
In a normal promise, I fetch right,
then I get the Json, and here,
finally, when I call it, I get the data, and only
once I get the data, I can start making things like filter
or mapping or things that I need to do,
right? So let's check the difference
with the task.
Cool. Here we are creating the task. As you can see,
it's exactly the same as the promise as we explained it before. But the difference
is that it's going to be lazy. So we are not calling this,
and let's check this difference without getting the
data, as you saw here before in the promise, without getting the
data here, I can start composing the functions.
So for example here I use a pipe.
Add pipe is a utility function in FPTs
that helps me with composition. So what it does is exactly
that, to work as a pipe, I get the data that
is running into another pipe,
which is going to map something, filter, transform,
reduce. I can compose and combine as many functions
as I want in order to handle the data,
right? So here what I'm doing is starting with a task which
is here, but I'm not calling it yet.
I am just saying that I'm going to use that task and
I want to map that task. This map is
more or less, you can think of it like
then in a promise for
the task. It's not exactly that bad. It's when you actually
resolve the task that you are passing here,
and then we can start making whatever we want without
calling the task first. So here what I'm doing is calling
a filter to get only the Javascript repositories.
Then I'm converting it to
a map to get only the names of those
repositories. And then I can set task
repos, I can console log, I can create an alert, whatever I want.
What I'm doing right now is just using
react user state to save that data here. So as
you can see, even though I do not
have called the task yet, I can start manipulating
or creating composition of that data, which give us a
lot of advantage when programming, and it is also more
referentially transparent. So I'm going to explain that a little bit later.
By the way, as you can see here,
if I call the pipe here, here at the end
of that composition is where I
call that task. Not inside, not before, after.
So I created here a function that is going to call that task,
and that is exactly what this thing is doing here. So let me
show you here in the code, as you can see the promise, run it immediately.
It does the things that it has to do. And if I run the task,
it runs the composition, the pipe that we
created, and that should be it.
Okay, let's continue with referential transparency.
I talked a little bit about this before, but let's check it
in the code to notice the difference.
I created a couple of functions here.
As you can see, we are creating an array
or a tuple of promises so just the,
no science, just create an array, I create a new promise
that is going to do something. Basically what it does is going to
resolve into can array of the promises that were called
here. So just call the promise here
and here and that's it.
So if I call this right,
as you can hear it says, as you can see here,
it returns me exactly that. I just run the promise number
one and the promise number two and that's it.
But this code seems a little bit repetitive.
So what we can do is just create a promise and then create
a functions that return a promise and then call it into the arrive,
as you can see here. Right. So what
I am doing here is creating a promise. I create it and
insert the promises that I want to run in here,
which should return to the same thing,
right? But it doesn't, as you can see here, it returns
only the first promise. Why? Again, because of bigger evaluation.
It is not lazy and it is not referential transparent,
because when we refactor this function
into something that should have had returned it the
same, it didn't. So it loses the referential transparent
that we think into functional programming, which is
if I create a function that something shouldnt
return a thing, but it doesn't, it returns another thing,
which means that it's less referential transparent
indifference with a task. So a task, as you
can see here, we are doing exactly the same as the promise.
We create a task here, we create
the array of tasks we call it,
and when we run it, it actually returns,
run it one and two. That is referential transparency.
Awesome. Okay, let's continue with short circuit.
This is something that we have all the time in
Javascript. So we create an EV that says
x or x is equal to one or
y is equal to two. So the
short circuit is that if one fulfills
the condition, it passes, it fulfills
the other one, it passes. If it doesn't fulfill both conditions
then it shorts circuits and it doesn't continue with
the process. That is it. So let's see
the difference on how promises and tasks handle this.
First of all, let's check how the promise was defined.
I have it here. What I'm doing here is just creating a simple promise that
is going to delay the printing.
And here what I am doing is a promise all which what
is supposed to do is to receive all the promises
into an array and solve them all.
If they succeed, then we console, if they
fail then we error. So here
I have an arrive with many delayed promises and one that is
going to be rejected. So what we might expect is that
if one or two succeeded and this one shorts, it quotes,
then this couple of promises shouldn't
run. But let's check how it actually handles
this. If I run the promise, as you can see,
it shorts it quoted the one that failed, but it
actually evaluated all the other ones that we had there.
And yeah, that is because the promises
actually doesn't have a way to run in a sequential form.
Only if we run them with then.
So we might have had to run it to wrote this
with the delay, then another delay,
then short seed quit and that would have stopped the
performance.
But let's see the difference with a task
here is the same. I just created a delay task that
is going to, let's see, I'm going
to show the taskeither later, but what it's going to do here basically is
to evaluate into something that is going to be
print in certain amount of milliseconds, otherwise print
errors. And here the same, I create the
array of tasks because I can actually create array
of tasks here. If I created the promises before, well they
might have run it immediately. But here I can actually create
this whatever I want into my code and then call it here.
So when I click on the result, the pipe
is going to receive the task array, which is the one that we have here.
Then we can sequence it. Because remember, when we have tasks,
we can actually compose the function before we
actually run it. So I can sequence these tasks,
then I can map them into console log.
And if they fail, this is the either.
If they fail, I can console log as anger.
Okay, so let's see how it works.
Run the task and it's evaluating the first one.
And as you can see, once it evaluates in the second one,
it immediately failed. And as you can see, the other
ones were not run.
So that's another cool difference that you can actually create
a sequence, you can traverse, you can do anything you want,
you can run in parallel with the task, which is
really cool. Awesome. Let's continue with another
feature that I think is one of
the best. It is the
errors handling here we are going
to be using not only a task, but a taskeither.
This is an algebraic data type. I'm not going
to go that much into that,
but adts are really awesome.
I strongly suggest you to check them, but taskeither is one of
them. Let's see why and how it works. As you can
see here, we are using taskeither same
library, fpts, and we are also using an taskeither
let me explain a little bit about the taskeither. The taskeither
in fpts is the way that we can handle the errors.
It is a much more strict way of error
handling. Also it's more explicit,
more readable. And basically what it says is that it has
a couple of possibilities. It can either be left,
which is for failed operations,
and it can be right, which is for the
successful ones, and that's the way
it can be handled. Also the types and stuff are
really clear on how to use them.
And another cool thing is that,
well, I will show you this. Let me see if I can
actually, let's run
it here, actually console log what
a response, this response is looking like
into the browser.
Let's see. So what I am defining here is just the user state,
which has a type of either. So as you
can see, either has the possibility for
us to let the developer know what is
going to be the error, what type is going to the error have,
and what type is going to be successful. So the error is
just going to be error. It can be an HTTP error, it can be any
error that you define it. And here I'm defining that. I'm going
to retrieve an array of GitHub repositories.
So let's see if I can show you how it works.
Here. It's an object.
As you can see, the response is not what we might
expect, like an empty are right immediately.
What it does is to create this tag that says
that it's right. If this left is going to be left,
and then it has the value right. Now it
has the value in the right. That is an empty Ari, which is
the one that we defined it here for default.
That is one of the main difference. So it actually obligates
you to tell if the
operation or whatever you are creating is either an error or a
successful type and task. Either is
the computations of the task, which is what we
just checked before, and an either, which is what I'll explain
it now. So task either is a promise that can actually fail
and that you can handle the errors with either.
Awesome. After that explanation, let's check
a little bit on the difference of how promises actually
handle the errors and how the task can handle it.
Here we have a promise, as you can see, nothing new. We create
a promise and that's it. But what happens if this
fails? We can actually let it pass and
do nothing, and we can actually omit
completely the catch and
that would make the program. Let's see how it works.
If I run the program with failure, it actually
runs here, the error, but it doesn't show anything to the user.
Or I don't know, if you don't have an
error boundary or something, it can make the application explode
in the browser and stuff like that. Right?
But we can also add a catch, which is a good
practice for the promises. But let's see the difference
here. If I write a catch here, let's see what type
the errors gives me. You can see it's can
any. So an error can be of any kind that
you want. That is why when you
control something into react or anything that you are building,
you can do whatever you want with the error. But as you don't know what
it is, what type it is,
it can always be confusing for the developer either to handle
it or to know what kind of error is actually getting
for me to handle. Right? So that is also one of the
disadvantages that the promises might have. But again,
they are awesome and it could work for sure.
But let's check the difference with
a task, right? So here I am defining the same
task, I am getting the
something. Also really cool is that for example in the promise
again, I actually have to define it like success promise,
failed promise, run it all again. But for example, in the task I
can actually define either successful or failed
one and I can pass it here as
a parameter, it's just a function into another
function as a parameter, which is, as I told you before, a functional programming
practice. Cool. So if I run the task here
with a task, either just these ones that we
created here, because this catch can either be an error
on a response or a response, the same here,
what is going to happen is that at first we are going to receive the
request, then we are going to can,
this is another kind of composition that we can do
to chain different asynchronous operations here.
So what I'm doing here is chaining and trying catch
the resolution of the data, right?
So if the request succeeded, then I'm
going to go ahead and get the JSON, return the JSON
to the developer to do whatever the developer wants to do,
and otherwise I'm going to have to return an error,
right? If I try to return like the typical,
I don't know, console log something,
this is immediately going to fail. Because we are defining that
the task either has to be either an errors or a response.
So we are forcing the developer to know that here we have to actually
return that type of error. And the same,
when we actually run the task and receive the data, we can actually handle
it like that. Right?
So let's see how it works.
If I run the successful task, it actually run
it like this, just normal.
If I run the failure task, I present the error,
right? So let's see how we presented the error
here. Let me check. Here it is
as we are defining the response,
which is an taskeither,
right. We actually don't have
a way to say,
I don't know, like map immediately into
that taskeither. You know what I mean?
Like for example, here in the success promise, we are going
to be able to map immediately into the promise response
map. And then we do it because the data is
what we got and then we do things,
right. But in the case of can taskeither,
we can't map into can taskeither because can taskeither is either a
left or a right. What we have to do is to fold it.
To fold it means that we can actually control what happens
when something turned it out to be an error and
what happens when something turn it out to be successful.
As you can see, there are a couple of arrow
functions that I define here. So let me remove this.
If I actually default, we're going to see the
typed much clearer, clearer. So as you can see, we have
the on left we're going to have an arrow function that receives an
error and you can return a react node or whatever you
want. And on the right we have that.
We are getting a GitHub repo array
and we have to return a react node or whatever you
want to return there. Right? So this
is something really cool that we can do with the ether
and tasks either. And here as we actually are getting
the GitHub repo now I can map what we
might have to do with the promises is actually here
in the catch, we might have wanted to set
error to something. Sorry about
that. To set the error to something,
I don't know, like it failed and
stuff like that. The same might happen in
the case of the loading. In the case, if it's not initialized,
we might have to set here all the user states
to handle those possible cases. Instead, here we
already have them thanks to the taskeither.
Right. So that is something really cool that we can
control and is also not useful. Not only useful,
but also restricts the developer on how to handle things.
Right. But as I said before, how do
I show the clients that my request is in
the pending state, in the loading state?
That can be kind of tricky and it has many different
or many challenges,
not only in the promises, but also in the tasks.
But I wanted to show you remote
data, which is here as
an alternative to use task eaters.
Okay, so let's see how it works around
here to remote data. And that's it.
So this is a different library,
remote data. TS is a library that is completely compatible with
fpts.
So we can continue to use that functional approach.
And what it does is to have
this remote data type which divides
the request or whatever asynchronous operation that we are
doing into four different types or states. The first
one is initial, which means that it hasn't been
called or anything. The second one is pending,
which means that it's actually started, but it's loading.
The other one is failure, which is failure, and success,
which is success. Right. So this is really cool,
because what we can actually do is not only set our
response into a taskeither, but into a remote data.
So response now is not can taskeither,
that can be a left or a right, but is a remote data that can
be in all of those states, right?
So the first state or the default one shouldnt be initial
because we haven't run the operation
yet, right. So when we define the
task, this is exactly the same. We define the task either
that can be an error or a response. And here
is where we can do like when it's initial.
If it's not initial, then it can actually be in
these different states. So we make the request and
I am adding here like can artificial loading,
just to show how it might load.
The other one is a can that
creates me the try catch to get the data
as we did before. And the last one is a catch,
which actually returns me. If it is
an error, I can set the response to be remote
data failure. And if it is a success, the response
should be a success. Remote data,
that's it. As you can see, we are piping this. Then we can call it,
we'll run it here and that should be it. So it's awesome. So when
we get the response, check it out how it looks in the code here.
You remember that before the taskeither, we folded. We can do exactly the
same here. Instead of folding the taskeither, we fold the remote data.
So let me check how it looks.
We try to fold here. As you can see, it says uninitial.
What happens on pending, what happens on failure,
on success. So it's exactly the same concept.
On initial, I'm going to show can alert, that says
not collect. On pending, I'm going to show the loading on
errors. This on response this,
and this is awesome because again we restrict the developer to handle
all the cases and also it's a lot more specific
for the user. Right? Check how it works here.
I'm going to make my network connection a little bit
slow to check how the pending works. And if I run, as you
can see, it does not call it yet. Then it says loading
takes a little bit and then we have the success,
which is awesome. If we make it fail,
I don't know. For example, let's try to call something that actually doesn't exist.
We are going to get the invalid Json, which is exactly what
we wanted, right? So that is something that
I wanted to show, which is really
code about remote data and how fpts and functional
approach can help us not only to improve the
promises, but also to get a lot more functionalities and
possibilities to handle our code in a
more functional way. Right? Finally,
what I would like to show is something
about another cool library that we have for
functional programming, asynchronous operations,
which is future,
right? So to make it short, basically futures
doesn't have taskeither or tasks or stuff like that, but it actually
has futures. A future is
what we can define as a lazy prompt in flutter,
right? It has exactly the same advantages
of a task either of functional programming.
You can compose it, it's lazy and everything, but it
also has can awesome feature, which is that it is
also cancellable, which means that you
can actually call a promise and cancel
it, or unsubscribe or finish it whenever you
need it. This is super useful for systems like
react or view or something that is reactive. Because let's
say that someone clicked into run this promise and
then click it another place that doesn't need that promise. If we run it
in the normal way, that promise will run until
it finishes. But here we can actually cancel it
when it's needed. So let's see how it works.
First let's check a little bit in the code.
So long story short, the same we define
the future instance, which is this one.
Here we create the future and the same as the
task. Either it can be an error or a succeed.
So here to make it sure, what I did is just to define a future
instance that is going to return something if errors or string
if succeeds. This is just the timeout that is
going to wait 3 seconds and return that my future was
fulfilled. And here is can awesome function,
which is the one that allow us to cancel whatever we were
running. So I just added here a console log and we clear the timeout.
Right. This is what is going to be called when we unsubscribe
this future instance.
So how do we run a
future? The only way to run it
or to do it is like calling it. You remember in taskeither
what we did was just call the computations
of the pipe that we created. But here we have
this function that receives a future. And if you can
pipe it again into a fork,
this fork is going to allow us to send the same
data as the taskeither. What happens when something is
unsuccessful and when something succeeded?
Right. That is it. What I'm telling here is that the future
I want to console log if it failed, and I
want to set the answer into my user
state here into whatever the
future succeeded to. Okay. And the final
function that I have here, this actually has nothing
to do with the cancellation itself, just a button that helps me
to call the cancel. But let's see, let's see what type
this one returns, which is the fork.
Right. It returns a
cancel. So it means that by default
whenever we call future, it returns
me a cancel. A cancel is a function that calls the
uncancelled callback or whatever you want to call it that is
going to stop my prompts to be resolved.
So what I did here is just to create another
function that is going to be called by a button. If the
cancel exists, then call the cancel. Oh,
sorry. Then call the cancel function.
The cancel function, as you can see what it is, is just this set cancel
that I am using here. I am going to show you why
this is because let's run it
here to explain that if
I run the future with this button,
it is going to start and
it's going to be fulfilling. So what this button did, let's check it
out. If I run the future, it is actually
going to set the cancel and run the future, which is this
function that returns the cancel. Right. So what I'm doing here
is actually creating or saving the
cancel function that was returned from the future into
this cancel user state, which is of typed cancel.
That is why we have to do it like that. I know it can be
a little confusing at first, but it's the only way that I can subscribe
into that future and I can cancel it later.
Right? So if I run the future again and
I cancel it, it immediately gets canceled and it doesn't returns
me the promise that I
ran it. So this cancel basically does that just
clear the timeouts or whatever catch that we might have
done and that's it. So it's really
useful for anything that you
might want to cancel. Whenever the
user is moving from one place to another, clicking one button and another
one, it's really useful to have this
cancel feature. Okay, awesome. And that was
it. So I will also like to mention other topics
that you can check.
Effects is library. It's an open source
library that allows you to build software in a
purely functional manner. And it's awesome. It's sort
of the competitor of future, but yeah,
once you get the concept and the mindset of functional programming,
it's going to be easier for you to use any of this.
Also rxJs, which can also help
you handle the premises in a more
observable way and in a more reactive way.
ADTs algebraic data typed are the basic concepts
of functional programming, and it's going to help you understand a lot more
how this whole thing works.
Functional programming itself, there's a lot to learn
there and you can always start checking things
with fpts. I would recommend for the front end
and you can always use it for backend applications
with node, which is awesome for creating
needleworks and validations. For example,
you can create simple and easy validations
with ioTs. Just going to help you have type safety
and validations immediately. It's really cool.
And besides that, just to jump into some conclusions,
I can say that promises are great,
but they can always be improved.
Functionet programming is a mindset,
a paradigm that can help you to have cleaner, more testable,
more control, and more readable code over all
your application. Please give it a try.
I know that the learning curve can be a little bit
high, but it's worth it. It's worth it to have different approaches
on how you can write your applications. Besides that,
use these libraries with caution because as
everything you can start implementing
them without the good practices or making them an overhead
can overkill into your application. So please use
them with caution. Try not to overload everything into
one application. Just decide what is better to your needs.
Also, something that I found with these libraries is
that documentation can be a little bit hard
and sometimes a little bit to understand and
to find in some cases. But the good
part is that they are all really well typed and
it helps you a lot when coding because the types can
self explain the functions and how they work by
themselves. So when you style the application, I'm sorry, when you
install the library, you're going to have the help of the
types and also some inside documentation that you have there.
But it's always better to have first a
clear idea of what functional programming is the basics
and then start using them. And last
but not least, enjoy programming. And thank you
very much for watching this talk.