Learning Functional Programming as an OOProgrammer

It’s been a while since the last time I wrote something in this blog! Well during the last years I’ve been working as a software developer, first as Fullstack Developer and more into Backend Developement in the last 1,5 years. I would like to continue developing my career in Backend, which I enjoy way more than Frontend. But sometimes, when I’m having conversations with senior colleagues I find it difficult to follow some of them, mostly because of the theoretical level they can reach. If that happens to you, you are not alone! We’ll get there, sometime (soon?). I hope.

So some of my coworkers are specially keen on Functional Programming (onwards FP) and they will talk about monads, readers, pure functions… and other terms without stop. At the beginning I had no clue what they were talking about and while I think sometimes these kind of conversations are an entry barrier for people that want to learn more about software development, I’m starting to learn the beauty of (some) of them, and that they are even needed.

Today I was reading on Object Oriented Programming (OOP) because it’s been a while since I don’t refresh all those concepts, and while I’ve been very invested on Node.js and Typescript, sometimes I still have to work in OOP, more specifically in Ruby on Rails. I just went to the wikipedia page on Object Oriented Programming and while I was reading about encapsulation I found myself thinking “wait, this is very similar to pure functions”. What is it happening? Am I starting to become a Functional Programmer? Since when I use FP concepts to understand OOP? WHEN DID THIS HAPPENED? Well, never, because I still struggle to understand what a monad is.

Pure functions in FP are those which 1) have no side effects and 2) you can always expect the same output if you pass them the same input, like developerName in this small code written in Typescript:

interface IDeveloper {
    name: string,
    surname: string
}

const developer: IDeveloper = {
    name: 'Cameron',
    surname: 'Crowe'
}

const developerName = (dev: IDeveloper): string => dev.name

Very silly example, I know

Encapsulation, on the other hand, is the way you structure your class so you can access data from the objects. You can expect the same behaviour when calling this method on the objects of the same class.

class Developer {
    name: string
    surname: string

    constructor(name: string, surname: string) {
        this.name = name
        this.surname = surname
    }

    developerName(): string {
        return this.name.toUpperCase()
    }
}

I can feel a similarity in these two concepts: The same way that you can always expect the same behaviour on pure functions, encapsulation allows you to expect the same behaviour when accessing some object’s data. In fact one of the benefits of encapsulation is that the external code doesn’t care about how you do it as long as you return the data, which makes it very easy for later refactoring 🤩. I like the idea of being able to represent an object and its structure but then have the freedom, flexibility and creativity of its internal processes.

You could say that encapsulation is a way to apply pure functions to objects or… that pure functions are encapsulated.

But wait wait… because this stops making sense when we come to the next OOP concept: inheritance. Classes can basically inherit everything from other classes, which it’s a nice concept for DRY (some people would discuss that then that new class is not needed, maybe?) but they can also OVERRIDE methods of those classes. So this is when my theory stops making sense, because then you can’t trust any object method if you aren’t sure of its class is.

class NewDeveloper extends Developer {
    developerName(): string {
        return this.surname.toUpperCase()
    }
}

And meanwhile this (polymorphism) is a feature for OOP it makes it very far away from being pure. You can no longer expect the same behaviour of a function based on its input, because it may be that there’s a class hidden somewhere that overwrote what the method that you are calling.

This being said, I still don’t like to be overly opinionated on what’s best (OOP or FP) because I’m still learning. And I also truly believe that OOP is a very nice paradigma for beginners as the fact that objects can be associated to the representation of things in real life makes it easier to understand how everything works. But I’m also starting to appreciate the beauty of FP, and how nice is to create transparent code and always know what’s doing, make it so reliable that you don’t have to care about black boxes that deal with your data. You only need to care about understanding for once what monads really are.