The Road to Functional Programming
Let's start by defining Functional Programming (FP). Wikipedia's definition:
In computer science, functional programming is a programming paradigm—a style of building the structure and elements of computer programs—that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data. It is a declarative programming paradigm in that programming is done with expressions or declarations instead of statements.
My interest in FP didn't come out of nowhere. This progression implicitly started through my interest in mathematics. In college, I earned a minor in Mathematics alongside a bachelor degree in Computer Science. However, the CS program strongly showcased procedural programming as well as object oriented programming (OOP) concepts. Coming out of college I was not aware of the FP paradigm. However, I was aware that I enjoyed mathematical theory.
Early in my career I was introduced to declarative programming by a mentor of mine teaching me about Language Integrated Queries (LINQ) in C# (shout out to John Avery). I was able to compare my previously procedural code which, at best, explained how the program was working with this new declarative implementation which clearly described what the program was doing. This was the first "aha!" moment for me.
The next light bulb moment happened when I realized that just by leveraging React in my projects I was unknowingly practicing some FP concepts via higher-order components, property immutability and component composition. This is when I decided to invest in learning functional programming.
The journey begins
The following professional project I worked on was a greenfield, large-scale web application for a country-wide insurance company. My coworkers and I made early decisions to leverage FP as much as possible. The first of which was to install Ramda instead of Lodash for working with our client-side data. Meanwhile, I was picking up beginner FP concepts through learning material such as Thinking in Ramda and Functional-Light JavaScript. These were great resources for grasping foundational concepts without having to tackle category theory or having to understand what a monad is.
It was soon thereafter that my coworkers and I realized we could only get so far in our practical experience using Ramda. We were using TypeScript on our project and there were some awesome Ramda functions that happened to completely abandon type safety. Now, we could have contributed the the open source types for the Ramda library or created our own types, however, we had client work to deliver and many of us were still in the early-stages of our FP learning. Therefore we resolved to avoid some fancy Ramda functions in favor of vanilla JavaScript.
The next step for me was to enjoy the LambdaCast podcast where the hosts strive to "describe concepts using clear everyday language without watering anything down". The subject matter of this podcast includes quite the deep dive into some great FP ingredients. That being said, the hosts do a great job of slowly increasing the complexity of the material while recapping relevant past episodes. What's more, one of the hosts starts with little-to-no FP experience (coming from a .NET development background) and is learning with the listener throughout the cast. This allows for an inexperienced FP developer to ask the experts good questions throughout the cast.
It wasn't long before some coworkers mentioned the Elm programming language. Elm is a statically typed, purely functional language for declaratively creating web apps. Curiously, I started researching Elm by reading through the docs which ultimately led me to read the Programming Elm book by Jeremy Fairbank.
There are many takeaways from all of this FP investigation but there are a few aspects to highlight, in particular.
Pure functions
The building blocks of the functional world. You can run a pure, side-effect-free function as many times as you'd like with the same input and always get the same output. These bad boys give the programmer peace of mind especially when combined with a robust type system and some parametric polymorphism1. Pure functions are easily testable and can reduce cognitive overhead when building an application.
Function composition
Another foundational aspect of FP is being able to combine functions together by passing the return value of one function as an argument to the next. This is very powerful on its own but becomes even more powerful when you incorporate partial application2 and currying3.
Immutability
If your data structures are immutable you don't have to worry about performing deep equality comparisons. Either the structure is the same or it's not. Nice and simple. Another bonus is that you will reduce the risk of accidental side effects4. How can you truly be certain that the logic you're writing around some data won't produce undesired results if that data can change elsewhere in the source code?
Learning curve
Make no mistake, coming from an imperative, OOP background and learning FP is no trivial endeavor. The barrier to entry is pretty high but the rewards seem worth it to me. Unfortunately, FP isn't the hottest buzzword in enterprise organizations. It would take some buy-in from stakeholders and team members to commit to leveraging a functional-first language such as Elm, Haskell, etc. Whomever works on the project would need to invest in the paradigm and that's just not worth it to some folks.
Hopefully FP can become more of a "main stream" paradigm in the community. While I can't help but feel like I've only discovered the tip of the iceberg here, I'm excited to learn how to scubadive in freezing cold waters.
- "In programming languages and type theory, parametric polymorphism is a way to make a language more expressive, while still maintaining full static type-safety. Using parametric polymorphism, a function or a data type can be written generically so that it can handle values identically without depending on their type." - Wikipedia↩
- "In computer science, partial application (or partial function application) refers to the process of fixing a number of arguments to a function, producing another function of smaller arity." - Wikipedia↩
- "In mathematics and computer science, currying is the technique of translating the evaluation of a function that takes multiple arguments into evaluating a sequence of functions, each with a single argument." - Wikipedia↩
- "In computer science, an operation, function or expression is said to have a side effect if it modifies some state variable value(s) outside its local environment" - Wikipedia↩