loading...
Cover image for Why you should learn Functional Programming

Why you should learn Functional Programming

anssip profile image Anssi Piirainen Originally published at anssipiirainen.com ・5 min read

Originally posted in Anssi's blog

Introduction

The first 10 years of my programming career, I was doing Object-Oriented (OO) programming in Java. I pretty much mastered the art of Object-Oriented programming as I had learned the design patterns to help me in coming up with class structures that avoid code duplication, and are flexible and adaptable for future change. My code was full of classes.

Things started changing when I picked up JavaScript, which did not force me to put all my code into classes. In my first JavaScript projects, the codebase still resembled the ones that I had been putting together with Java. I was not using classes, but despite this, some of the files still had a look&feel of a class. The code had modules that grouped functions that were somehow logically related to each other, just like a typical "service" class in Java would have.

Today I have programmed in JavaScript for more than 5 years, and my coding has evolved a bit. I have started to think of my programs as data processors. There is always some data that needs to be processed. I think about what kind of processors and functions are needed to transform the data. My studying of Functional Programming has profoundly influenced me, and this data-centric approach arises from this studying and learning.

In this blog piece, I explain why it has made sense for me to study FP and why you should also learn it.

The Benefits

Experienced functional programmers can tell you about the many benefits of functional programming:

  1. Functional code is easier to understand
  2. There are fewer bugs
  3. The code is more compact
  4. Some even claim that it's easier to test and debug

I agree with these claims. The difference between paradigms is easy to see If we take a non-trivial programming challenge that has implementations both in a functional and in a traditional imperative style.

Imperative implementations for a complex problem can be hairy with nested loops and nested if-then-else statements, class inheritance structures and all the things that we typically see in imperative programs.

Have you ever studied a big object-oriented program that was done by an experienced OO practitioner? One that is well-factored to use classes with clear responsibilities. One that does not have any duplicated code and is DRY. Factoring code into classes with distinct, clear responsibilities removes code duplication. This kind of designs can include several hundreds of classes. It can be tough to see how this program works and how the different classes work during runtime.

A well-factored functional implementation, on the other hand, might look scary when you first look at it, but after a little bit of studying, you should be able to understand the pieces (pure functions) that it has and how those are composed together.

You can understand each function in isolation. You can trust that the program does what is promised.

Challenges

Contrary to what I just said in the paragraphs above, functional programs can be hard to understand for programmers that are not familiar with the functional style. Functional code can look quite different than the imperative counterpart. You cannot see many occurrences of elements that you are used to seeing in code: There are not many if statement, or for loops, for example.

All you can see is a bunch of small functions and weird-looking compose(), and pipe() calls that might make no sense to you are not yet familiar with these concepts.

There is a learning curve to understanding FP. First of all, you need to study the basics, and once you know the basics, you can start ramping up your knowledge little by little. There is a lot to learn before you are a master FP practitioner. I have been on this learning streak for one year now, and I'm still at the beginning of my journey. I'm sure that I'll reach the master-level status someday if I just continue working hard towards that goal.

I have a 10-year history with object-oriented programming using Java. I was a huge fan of the Eric Evans' book Domain Driven Design and took it's teachings about Entities, Services and Value Objects seriously. I have implemented thousands of classes using the patterns explained in the Domain Driven Design and the GoF Design Patterns books. Because of this background of mine, FP made little sense to me when I first looked at it.

I found debugging functional code to be challenging. Where do you add your breakpoints, when all you have is a list of functions linked together using pipe? Debugging is another area where you need to learn new tricks because the old ones don't work with FP. Luckily there are plenty of strategies for debugging functional code.

Learning Functional Programming

Why would you take the effort and learn FP? I guess the most important reason is that learning it makes you a better programmer. You can benefit from knowing about FP even if you continue doing object-oriented programming. Making functions pure and favouring immutability are great habits, no matter what your primary programming paradigm and programming language are.

You don't need to go full-on with functional and scare your co-workers by coming up with code that is so full of currying [link] that you need a degree in Indian cuisine to understand it. I would recommend Kyle Simpson's book Functional-Light JavaScript to get you started. It provides a pragmatic, balanced way of doing FP in your JavaScript projects. It is the book that got me started with FP.

Ramda is an excellent functional toolkit library for JavaScript. You need something like it to ease your life. It contains the functional "primitives" that you can start using in your real-life projects.

Mastering FP takes time. I'm at the beginning of my journey, and my journey so far has looked like this:

  1. I read the Functional-Light JavaScript book and got excited
  2. I started sprinkling in FP to my daily projects. I started making my functions pure and started avoiding mutating my data.
  3. But then I got busy with daily projects, and my FP learning ambitions got sidelined...
  4. Then luckily, I became less busy again, and my FP learning was back on track.

I think it's essential always to study and learn more. In this profession, it's a must. If you stop learning and improving, more ambitious programmers overshadow and take over you. Eventually, you give up programming and become a Manager and, for sure, that is a scenario that every self-respecting programmer wants to avoid :-)

Discussion

pic
Editor guide
Collapse
ahferroin7 profile image
Austin S. Hemmelgarn

On your four listed benefits to FP, I'd contend that they aren't exactly as clear cut as many people make them out to be:

Functional code is easier to understand

This one isn't universally true, and it can actually be patently false for some people. Some aspects definitely are easier (for example, not needing to deal with mentally tracking the meaning of this in JS due to using functional constructs is a huge plus to understandability), but some of the core concepts of FP, like recursion, are actually pretty hard for some people to wrap their heads around.

There are fewer bugs

This isn't always true, and when it is true, it's usually a side effect of improved readability and testability. You can also run into a whole slew of bugs in FP that you're not as likely to encounter in OO, procedural, or other paradigms (recursion is a big offender here, though that's not so much FP as recursion itself).

The code is more compact

Not necessarily. Functional programming languages tend to have a more compact syntax than OO languages, but that's language design more than anything else. A lot of OO or procedural languages could be much more compact if they implemented some of the non-FP specific stuff found in certain FP languages (like pattern matching in Erlang). Certain operations are definitely more compact written in a functional manner (map and reduce for example), but some others are much smaller in an object-oriented or procedural implementation (for example, trial division is more compact in most mixed-paradigm languages when done in a procedural manner than a functional one).

Some even claim that it's easier to test and debug

The testing aspect is a mixed bag. You can much more easily mock-out components in FP code because dependency injection is a rather strict requirement of good functional code, but you can do just as well by making it a strict requirement in OO code. In contrast though, you may need to jump through hoops to make certain things realistically testable in functional code. Part of this is also a result of some higher profile FP languages having very good testing integrations as part of the base environment.

Debugging I'd say is more a side effect of the other aspects than anything else. Easily readable and efficiently concise code is usually easier to debug regardless of paradigm, and FP kind of forces you to avoid certain situations that are inherently hard to debug. It can be more challenging in some cases though, such as when dealing with a well written recursive function in a language with proper TCO.


Note that I'm not trying to discount your argument here. I agree that learning FP is a good way to broaden your horizons as a programmer (though I feel similar about OO, procedural, and most other paradigms), I just feel it's important to understand that most things people tout as benefits of a given paradigm are often have stipulations attached.

Collapse
juancarlospaco profile image
Juan Carlos

I tried to do the same, but vanilla JS wont offer too much benefits for functional,
mainly when you code with other people that may not take that much attention to functional aspects,
so it works when coding alone but not coding with other people or on groups,
then I tried TypeScript, it wont offer too much benefit over vanilla JS for Functional,
then tried some Functional-oriented frameworks for JS but that wont play nice with OOP if needed to,
then I learned Nim, it offered simple but useful advantages, to name a few:

  • Immutable by default, no global mutable state unless you want to.
  • Compile-Time truly immutable, run-time truly immutable.
  • Immutable function arguments.
  • Immutable compile-time function execution. Compile-time FFI also possible.
  • Side-Effects tracking, with compile-time enforcing.
  • Pure functions, with compile-time enforcing.
  • Light-weight OOP if you need it. Design By Contract, Chaining, Pipes, etc.
Collapse
dhihendrix profile image
Collapse
anssip profile image
Anssi Piirainen Author

Thanks, Dhiego! I appreciate the feedback.