How Functional Programming made me a better programmer

Marcos Hernández
CodeSyndicate
Published in
3 min readMar 20, 2017

I’ve been programming almost all my adult life. I’ve tried a ton of languages, mostly the mainstream ones; Basic, Pascal, Java, C, PHP, Python, a bunch others, and of course JavaScript. But also I was kept in the Bliss of the holy world of Imperative Programming and Object Oriented Programming.

So, fast forward to just a couple of years ago. I started to read everywhere the term “Functional Programming” (and its always present companion: Haskell) though not totally alien to me. I knew it was one of the “Formal” methods of programming. It was deeply rooted in Math and Logic and it was totally useless in a real world application. I even used some “functional features” in python and even in JavaScript (later I found out Brendan Eich intended JavaScript as a totally functional languages pretty much like scala before Netscape slapped him with the Business Rules that didn’t include functional programming).

But still, nowadays I spend plenty of time reading and decided to go deeper into the topic and stumbled into this article by Paul Graham (link to the complete article in postscript here)

It. Blew. My. Mind. Here are some of the things I learned by applying Functional programming to my code:

1. Back to basics: Divide And Conquer

One of the foundations of Functional Programming (FP) is the use of Pure Functions; that is: when you write your functions, you do it in a way they depend only on the arguments passed and whatever other value is in the scope of that function (in any language that supports FP, functions are values).

I tried playfully to solve puzzles using this restriction. Little by little I started to see problems in a new (old) way: big challenges only accomplished by decomposing in small, simpler, parts that could be solved using Pure Functions. It was going back to basics: Divide and Conquer; and separate concerns.

2. Testing is fun again

You know how it goes. You commit to TDD, write your assertions, and with a proud smile on your face, start tackling down all you test failures. But pretty soon one of your classes start using another class to retrieve data, in order to ensure a reliable service you use a singleton (or how I call them: The Demon Lords of the Pastafarian Hell) and you inevitably start investing more time writing mocks than actual coding. Soon you start to realize that your unit tests have become almost an E2E test (or how I call them: Abominations of Vhrool Planet in the 23rd nebula from Nug and Yeb).

Ever since I started a more functional approach to my code, I can go back to testing with a saner dependency management. Since a function is pure, it cannot rely on any external resource. How do you resolve this? With delayed evaluation: You derive a new function with the injected dependency, then you can safely call the new function with the injection closed over.

This means you can keep your mocks minimal and you can inject them directly in your tests, no need to expensive setup before testing.

3. Find a new medium to express meaning

Another foundation of FP (more like a mantra, at least for me) is that the functional programmer don’t write “instructions” or “recipes” but rather write define things through functions. My code now looks more like a dictionary than a cookbook, and that’s a good thing. Is truly self documented code. I’m defining how the data looks for the purpose. I’m not tossing away regular documentation, you should still write proper documentation; but following other good practices, for example: giving meaningful names to values. Writing short pure functions made my code way more readable and easy to follow.

4. Less Code. More Abstraction

Now I write less code in each iteration. That comes hand in hand with the divide and conquer concept in point #1. If you organize your code in small functions that solve specific components of the problem, is easy to spot patterns and once you detect a pattern you can abstract functionality and call your abstraction anytime you need it.

On top of that, if you define your abstractions with composability in mind you can reorder your function to extract and transform your data any way you need. And if you did your homework and have your proper tests, if you break any abstraction trying to refactor, you will immediately notice.

--

--