Why You Should Learn Functional Programming

OOP is for old people

Daniel Kulangiev's profile picture

Daniel Kulangiev

Full Stack JavaScript Developer

ยท 5 min read


Whether you are brand new to the world of JavaScript or already a seasoned developer, you may have come across a term called "functional programming." Without making this post too dry or diving deep into functional programming, I will show some examples and let you decide which style is more readable (your future self will thank you).

So, what is functional programming?

It is a style of coding that has been gaining traction as more and more developers start to adopt the paradigm due to its declarative nature. Some benefits of functional programming are:

  • Boosted readability on your codebase.
  • Writing code becomes more manageable.
  • JavaScript skills get reinforced.

At this point, you might be thinking, "wow, that's a hell of a sell for functional programming!" However, adopting this style (or paradigm) is notoriously known for having a steep learning curve. If I can teach you functional programming in one blog post, then this would be it. Unfortunately, just like most things that we learn about in programming, we must find multiple resources, understand them, apply them, and restart the cycle. That being said, let's take a high-level dive into how our code can be significantly improved by the points mentioned earlier. I will include some great courses at the end of this post if this ends up being a journey you are willing to take (it is worth it!).

Boost in Readability & Manageability

Let's look at how we might code up a simple example of processing a player's name through several functions.

const player1 = { name: "daniel kulangiev", score: 3, }; const getPlayerName = player => player.name const getFirstName = fullName => fullName.split(" ")[0] const upperCaseFirstLetter = str => str[0].toUpperCase().concat(str.slice(1)) const addUserLabel = name => `Hello, ${name}` const fullPlayerName = getPlayerName(player1) const firstName = getFirstName(fullPlayerName); const upperCasedFirstName = upperCaseFirstLetter(firstName); const labeledName = addUserLabel(upperCasedFirstName); console.log(labeledName) // LOGS: "Hello, Daniel"

In this example, you probably noticed that we create multiple variables to store the result of running a function (getPlayerName, getFirstName, upperCaseFirstLetter, and addUserLabel). But, How can we capture a result without storing it in a brand new variable every time?

One way is we can COMPOSE the functions by implicitly returning the result into the following function call. For example:

const player1 = { name: "daniel kulangiev", score: 3, }; const getPlayerName = player => player.name const getFirstName = fullName => fullName.split(" ")[0] const upperCaseFirstLetter = str => str[0].toUpperCase().concat(str.slice(1)) const addUserLabel = name => `Hello, ${name}` addUserLabel(upperCaseFirstLetter(getFirstName(getPlayerName(player1)))) // OUTPUT: "Hello, Daniel"

Wait, that's even harder to read! You might think, and I agree with you. Now, this next piece of code I will show you uses the Ramda library, a popular functional programming library, to achieve the goal we are looking for without focusing too much on the implementation details. The Ramda library allows us to just focus on using utility functions such as compose and not have to rewrite them every time we deal with a new project (you may also code up the compose function yourself).

const player1 = { name: "daniel kulangiev", score: 3, }; const getPlayerName = player => player.name const getFirstName = fullName => fullName.split(" ")[0] const upperCaseFirstLetter = str => str[0].toUpperCase().concat(str.slice(1)) const addUserLabel = name => `Hello, ${name}` const log = val => { console.log(val) return val } const playerGreeting = R.compose(addUserLabel, upperCaseFirstLetter, getFirstName, getPlayerName) playerGreeting(player1) // OUTPUT: "Hello, Daniel"

Much better! We can see that the functions are "chained" through this compose function to give us a new function to be called with the data we want to be processed. You also probably noticed that the functions are being executed from right to left (starting with getPlayerName); this is a bit weird getting used to. However, suppose you go back to our previous example with nested functions. In that case, you can see that the innermost function is getPlayerName, and the outermost is addUserLabel (which ends up being on the left side). If this seems unnatural to you, the "pipe" method is also available with Ramda, which executes it from left to right instead.

Finally, we are left with a much more declarative style of code. Understanding how utilizing a technique such as function composition allows for far more readable code and aid us during development (for example, what if we wanted to add another function in the pipeline such as appendLastName or incrementScore).

Although I've barely touched the surface of functional programming, I wanted to briefly glimpse into that world and showcase a critical part in it with function composition. If you are interested in learning more about functional programming principles (such as higher-order functions, partial application, currying, closure, reducers ...etc.) I recommend starting with Will Sentance's course: The Hard Parts of Functional Programming on Frontend Masters. I recommend checking out the other functional programming courses on Frontend Masters once you get the basics down.

Recommended courses for learning FP


JavaScript
Functional Programming
Share

Stack Five is a React and NodeJS consulting company that strives to push the boundaries of the web and build meaningful things. If you're looking to create a cutting-edge web application or need software engineering resources for your project, please contact us.

Stack Five logo

2021 Stack Five Inc. | Toronto, Canada