Back to all blogposts

7 reasons to use functional programming on frontend 1/2

Wiktor Toporek

Wiktor Toporek

Senior Frontend Developer

Functional programming has recently become a big thing in the frontend development domain. Why so? Is it an example of hype-driven development or are there any reasonable arguments to use it? To answer this question, I’ve prepared a list of seven reasons which may make you decide to use functional programming on frontend during your next software project. Below, there are the first four of them.

In the first part of the article about functional programming on frontend, I’ll try to cover a few topics. What is functional programming? What are examples of functional programming languages? What is functional programming style? What were the issues with functional languages in the past? What is function in programming? What are some of functional programming examples? And finally – what are the real reasons to use functional programming on frontend?

1. JavaScript object-oriented programming used to be weird in the past (functional programming language issues)

This is one of the reasons why functional programming on frontend might have gained such popularity rather than an argument to use functional programming paradigm. Although, it’s worth mentioning this “weirdness” in the name of the better context. A little bit of history…

In the early days, object-oriented programming in JavaScript used to be slightly weird. It was possible to use this kind of programming, however it wasn’t even close to the OOP known from C++, Java or other popular OOP languages. There were some issues with functional programming languages. Just take a look at this example:

It’s due to the fact that JavaScript offered a prototype-based inheritance in contrast to class-based one which is the most popular approach in other object-oriented programming languages. So, why JavaScript took the other way?

In the 90s, we had less powerful computers and obviously, less sophisticated browsers. When JavaScript was invented, prototype-based inheritance has been chosen. It was easier to create an interpreter for it and preserve OOP features at the same time. And probably that’s the reason.

Before the age of transpilers like Babel and alternative frontend programming languages, there was almost no alternative for programming language than ones ran in a browser. If we exclude plugins like Java Applets and Flash. Oh… and VBScript which worked on the famous Microsoft Internet Explorer only.

It took 20 years before ECMAScript 6 with final semantics for classes were introduced

What’s more, it took 20 years before ECMAScript 6 with final semantics for classes were introduced. Before that, people got used to the prototypes and some of them also made use of JavaScript functional programming features. These were truly powerful concepts and were available a long, long time before ES6 classes.

Hence, it might be the reason why not all the people adopted ES6 classes syntax in their codebase. Of course, classes have become popular in React or Angular based apps, although considering standalone micro-libraries which NPM repositories are famous for, the class keyword is rare and functional approach beats it.

2. Immutability can reduce bugs

JavaScript is now something more than just an extra script

Thanks to the solutions like single-page applications, JavaScript is no longer just an extra script that improves the user experience when navigating through the page. Enabling JavaScript support in the browser is something you must do if you want to surf the internet these days.

Sites became applications and the bigger apps are, the more complex issues developers have to deal with.

Frontend developers already have a “bug-friendly” environment thanks to the things like:

  • browser inconsistencies,
  • innumerable amount of devices with different parameters where the app should display correctly (responsive web design tries to deal with it),
  • API connection problems which have to be handled neatly.

And many more. So, naturally, tools and approaches which help narrowing the scope of problems down are highly appreciated.

Functional programming itself has more strict variation called “pure functional programming”. Pure FP is a paradigm that imposes strong restrictions: immutability and side-effects avoidance. At first glance, these may feel like an unnecessary complication (especially for developers with an imperative programming background). But they bear fruit when it comes to the master application state.

In terms of immutability, let’s study the two following functions:

Perhaps you have already spotted a bug. ???? Nevertheless, let’s test their behavior in JS console:

> median([2, 1, 3, 7, 2, 4, 0, 5])

> getLast([2, 1, 3, 7, 2, 4, 0, 5])

They seem to work properly and would pass the unit tests easily. But note what happens in the following code:

The console.log output for such case is:

  • 5 for getLast which is correct,
  • 2 for median which is not the value that we expected.

The problem is that values.pop function inside getLast function mutates the array which is passed into by popping the last of elements.

So, let’s redefine getLast function with immutable (or, so called, pure) principle in mind:

Then, let’s try again:

Did it work as expected or not? Well, there’s another bug we might have missed.

Let’s try to change just one, tiny thing. Namely – let’s swap the console.log lines:

The console.log output is as follows:

  • median gives us 2.5, as we expected,
  • getLast gives us… 7!?

The problem here is that our median function is not pure. It mutates the array that is passed in as it was in our first implementation of getLast.

What makes this function not pure is that it calls another not-pure function – Array.prototype.sort:

Array.prototype.sort behavior may confuse. It returns a sorted version of an array that has been passed into it, although the sorted version is just a reference to the original array which has been mutated.

Taking the functions from preceding code examples into consideration, we can see that mutation made them not working properly when we used them one by one and swapped the order of their execution. It has revealed another bug which might have been missed at first glance.

So, let’s finally fix the code example:

What we’ve done in the code above is that we implemented a sort function. And it does not mutate the original array.

Our pure sorting solution makes use of a simple trick of calling Array.prototype.slice(). It creates a copy of the original array before sorting. This behavior guarantees that our sort function won’t mutate the passed in argument, hence it is pure.

And as we use our pure sorting function in the median function, it’s also pure. It guarantees that median won’t mutate the argument neither.

Now, no matter which function is executed at the first place, the results are always predictable and correct:

3. It’s easier to test (and pure function can help)

No matter which programming language I use, there’s a thing that I always associate with tests. It’s mocking/stubbing. When you write unit tests, sooner or later you’ll have to fake some objects and functions that tested unit relies on.

Pure functions can help you with that. The way they work is simple:

Here is how pure functions work

just compare them to functions that are not pure:

Here is how non-pure functions work

Due to the fact that in pure functions there is no mutation, side-effects and functions have referential transparency (we’ll focus on this later), it’s guaranteed that the only place where you can change the result of such function are arguments that are an input.

Consider how much easier is writing tests for functions that rely only on what you pass to them explicitly. For instance, functions that have to deal with date and time. Normally, it would be tempting to write such a code:

But because such function relies on the current time (which passes by), you’ll have to mock fthe date object before testing the function. Although this function is easy to write, it’s more difficult to test, as it requires you to fake the time when writing the tests.

Referential transparency is something that can help us in such cases because it guarantees that the function is deterministic. Referential transparency guarantees the specific input which will always give you the same result – no matter how many times (and when) function is called. Hence, call expressions of functions that met the referential transparency condition can just be replaced with output value like in the following example:

The number variable can be replaced with the following:

let number = 4;

So, coming back to our tokenExpired function example. We can rewrite it to a pure version which meets the referential transparency requirement:

This function will no longer depend on the current time behind the scenes, and the tests can be simplified as the current time has to be passed explicitly as the second argument:

4. Time-travel debugging

Sometimes going back in time is the only way to fix a bug

Have you ever used Redux DevTools? It’s a very helpful tool if you want to debug React + Redux combination based app. Redux is a library capable of managing app state. One of its core principles is the ability to change the state only through pure functions.

The assumption that the app state is modified only through pure functions makes it simple to go back in time and study the application state. For example – right before a bug occurred. In fact, pure functional programming makes the “undo” feature easy to implement. It’s because you have a guarantee that before a new state is presented, the former one is not affected, so it can be easily stored in history.

However, Redux is just a JavaScript library and cannot enforce developers who use it to avail themselves of pure functions. Moreover, typical React app is not only about the state. There are many side effects to be made, AJAX requests to be sent, some components with their own state to be rendered in the DOM and so on. Because of that, Redux and Redux DevTools may get tricked if a developer does not follow the pure functions convention. But there are some alternatives which can fix that problem too. One of these is Elm programming language.

Using Elm can help you solve some problems

Elm is a frontend programming language which compiles to JavaScript. In contrast to JavaScript, it’s a pure functional programming language. One of the fun features which Elm offers is a time-travel debugging which is not limited to a raw app state as it is in Redux DevTools. In Elm’s Time Travelling Debugger, it’s possible to go back in time and observe the real app (instead of its raw state tree) in the way the users see it in their web browser.

What’s more, this tool can also import/export app state so a developer can debug any state saved in a file. This can be helpful not only for debugging sessions but also can give the QA team another tool that can improve the bug reports.

In fact, Redux has been inspired by Elm. Also, Dan Abramov (the creator of Redux) has been inspired by Elm Time-Travel Debugger and you can watch his cool presentation how he achieved a similar effect for React + Redux.

To be continued…

In the first part of the article about functional programming on frontend, I’ve focused on the history of JavaScript’s object-oriented programming early state. I’ve mentioned how it might have generated interest in alternative or subsidiary approach which functional programming can be.

We’ve also learned some basic features of functional programming on frontend in practice. You saw an example of functional programming too. Nevertheless, these features are universal and frontend is not the only domain which can benefit from it. Having some basics though, we’re ready to study some further FP programming examples.

So, stay tuned. In the second part, we’ll focus on another three reasons to use functional programming on frontend. I will focus on functional programming patterns, the topic of declarative-style which is readable when describing visual aspects and we’ll take a closer look at straightforward optimization on functional programming. I’ll answer a few questions, such as: does every JavaScript developer these days have to deal with its asynchronous nature? Is functional programming a declarative paradigm? What are functional coding and functional coding concepts? How virtual DOM, concurrency, parallelism, memoization can help when it comes to functional programming on frontend? Sounds good? More to come in the second part.

You may also like

State of Frontend 2022 - Global report

With 3700 devs, 19 experts, 13 topics. This report will rock your front!

Claim free copy

What would you like to do?

    This site is protected by reCAPTCHA and the Google
    Privacy Policy and Terms of Service apply.

    They are more than just a software company. They are the partner who will help you achieve what you want to achieve.

    Nick Gold

    Managing Director at Speakers Corner


    Thank you for your inquiry!

    We'll be back to you shortly to discuss your needs in more detail.