Instructor: By now, we learned a lot
about keeping our list of function parameters short
and concise and keeping the function body short and concise.
Now, there is another aspect of writing clean functions,
which you should keep in mind.
And that is that you should try to keep your functions pure.
Now, what does that mean though?
What is a pure function?
A pure function is simply a function,
which for the same input generates the same output.
So for the same input parameter values,
you always get back the same output.
And this here would be a simple example.
This generateId function.
It takes a userName as a parameter.
It then combines that with the hard coded string
and then it returns this id string, which was generated.
Now, as you can see, if you have a look at this code,
for the same userName value, like Max,
we will always get back exactly the same returned value.
This is a function, which is 100% predictable
and which, therefore is pure.
Now, here's the same function again,
now, however, defined as a impure function.
This function, unlike the first one,
does not always yield the same result
for the same input
because we do generate a random number,
which we convert to a string,
which we then combine with the entered input value.
So for the same input value,
we will always get a different output value here.
Hence, this function is not pure.
Now, it's not necessarily bad to have impure functions
in your code and in your program
because sometimes, you just need something like this.
Sometimes you might need to generate a random ID
and return that.
So it's not the case that impure functions
are always bad but they are definitely less predicable
than pure functions
and hence, you should only go for impure functions
if you really need that behavior.
And that's especially true
if we don't just consider the generation
of a random value as part of your function
but if we specifically have a look
at another concept, side effects.
Pure functions shouldn't have side effects,
which again, does not mean that you are not allowed
to have side effects at all
but a pure function wouldn't have a side effect
and therefore, you might wanna minimize the number
of functions that do have side effects.
Especially when following a functional programming approach.
If you're really trying to strictly follow such an approach,
it is quite common and expected
that the vast majority of your functions,
which you compose and combine together
are side effect free and pure.
And then you would only have a couple of places
in your code where you do have side effects.
Now, of course, you don't have
to follow the functional programming approach.
You could have an object-oriented approach
or a mixed approach, an imperative way of writing code
and therefore, you don't always have to be that strict
but in general, as you will also see over the next minutes,
side effects are definitely something you should be aware of
when you write clean code.
But for that, let's first of all,
clarify what actually is a side effect.
Well, here's a simple example snippet.
This createUser function
does what the name implies.
It creates a user by instantiating a user object
by using the constructor
and then it returns the user.
So like this, it would be a pure function.
It will always give us the same kind of user object
whenever we run this function.
However, let's now say we have this line of code
in the function as well,
this startSession line of code.
Now, this function, which we call here,
is very likely to change the overall state
of our program.
And that's what we call a side effect.
It's an operation, which does not just act
on the function inputs and change the function output
but which instead changes the overall system
or program state.
For example, startSession could change some variable outside
of this createUser function.
And when you have such a side effect,
a function is also not considered to be pure
because even if it does always return the same value
for the same input,
if it does something else in addition
to the work it does on the inputs,
then it's also not considered to be pure.
So a pure function is only pure
if it always gives us the same output for the same input
and it doesn't have any side effects.
But what's the problem with such side effects?
Again, you won't be able to always avoid them.
Indeed, depending on the kind of program you're writing,
you might need a lot of side effects
because there are a lot of potential side effects,
starting sessions, sending HTTP requests,
even logging something to the console
or showing some message to the user
would all be a side effect
because it's a change to the state of your system
and of your program, right?
I mean, if you show something to the user,
that's definitely a different state your program is in
than a second ago when you didn't show a message.
So these changes are everywhere
and side effects are everywhere.
But side effects do become a problem
if they are unexpected.
They're not automatically bad.
We need them but if your side effect is unexpected,
then it is a problem.
For example, in this createUser function,
you could kind of expect a side effect,
maybe createUser implies that the user is also stored
in a database and that would also be a side effect.
Starting a session could also be a kind
of expected side effect.
So in this example,
it might not be a bad side effect at all.
But consider this example here.
It's again the generateId function
but now it's not just generating and returning an id,
it's also assigning that generated id
to some global state, to some global variable,
which we have in this program.
This is a side effect
because it's not just work we do on the input and output
of this function, it is work we do
on some other variable in our program.
Now, maybe we need to keep track
of that lastAssignedId.
Maybe that is some internal work we do
but maybe it's also not something we expect
when we call a function named generateId.
Maybe a simple change in the name
to generateUnusedId would suffice here though
to make it clear that this function
will need to check whether an id has been used or not
and that therefore, it might also interact
with the global system state.
So that could be one possible fix here,
instead of just keeping the name generateId like this.
Because that is the strategy
for avoiding unexpected side effects.
As I said, and I really wanna emphasize this,
side effects are not necessarily bad
but your naming matters.
Side effects do become bad if they are unexpected.
And therefore, the name of a function should signal
or imply that a side effect is likely to occur.
Otherwise, it's considered a bad side effect
and therefore, not clean code
because clean code doesn't do unexpected stuff.
Clean code is well, clean, easy to read
and easy to understand.
And if something happens, which you didn't expect,
you clearly did not understand the code,
hence the code wasn't clean.
So have a look at these example names here, for example.
If you see functions named like this,
where would you expect a side effect?
In saveUser we do expect one I would argue
because saveUser implies
that this user is probably going to get saved
to a database and saving data to a database definitely
is a side effect
because it does manipulate the overall system
and program state.
After all, we write a new entry to a database,
we change files.
This is a crystal clear side effect
and we do expect such a side effect
for a function named saveUser.
On the other hand, if we had a function named isValid,
then we do not expect any side effects there.
We do expect that this function maybe answers the question
whether some input or some email address is valid.
It would be much unexpected
that this function then sends a message,
writes to the file system,
shows a message to the user
or changes any other program state.
Now, what about showMessage?
showMessage, per definition,
will have a side effect.
If we show a message to the user,
no matter if that's the terminal or console
or if that is an overlay on a website,
if we show a message to the user,
we are definitely changing the program state
because the state will be a different one
if we have an overlay on the page
than it was a second ago
when the overlay was not there.
So here, because of that name,
a side effect would be expected.
Now, what about createUser?
Here, I would say you could go either way.
You could say that you don't expect a side effect
because a function named createUser
will probably do just that,
create a new user.
On the other hand, create is a very wide word
with a lot of interpretation you can put into it.
Create could mean that saving that user
to the database is part of the creation process
or that validation of the inputs
and showing an error message is part
of the creation process.
So here, it really comes down to the overall context
of the application in which you use this function.
A side effect is not necessarily expected I would say
but it's also not totally unexpected.
And over the last lectures,
we indeed, had a function named createUser,
which did have various side effects.
And therefore, long story short,
the idea is simple.
It is okay to have impure functions
and it is okay to have side effects.
But whenever a function is impure,
typically because it does have a side effect,
that should at least be expected.
Your functions should not have unexpected side effects
and if you have a side effect
or if you need a side effect,
you should therefore either choose a function name,
which implies that.
Then it's absolutely fine
or you should move that side effect operation
into a different function where it again is expected.
This is important to ensure that you have clean code
and clean functions
because it's definitely not clean code
if your functions do something which is not expected.