Humans are addicted to binary choices.
This is one of the plagues we carry with us in the 21st century despite the world having become more complex than ever and our challenges being everything but binary.
Many battles have been fought, and some of them still are, both in the real world and on internet. I’m sure you’ve heard some of those:
- iOS vs Android
- PC vs Mac
- Internet Explorer vs Netscape Navigator
- SQL vs NoSQL
- Playstation vs XBOX
- Coke vs Pepsi
- Despicable Hawaii Pizza lovers vs the wise and healthy rest of the world
But there’s one more battle. A battle that is closer to us as Software Developers than every other.
I’m talking about the endless war between Object Oriented Programming vs Functional Programming.
The question everyone tries to ultimately answer by annihilating the opponent is: which one is better? OOP or FP?
Hordes of object oriented hands-on developers clash daily with armies of functional programming purists in a never-ending battle for who has the best paradigm.
“We built Facebook with PHP! Wikipedia! Wordpress! We own 99% of the web!” — screams one side.
“Our software can’t fail by design! You reject FP because you’re not able to understand it! Endofunctors are the new black!” — roars the other.
And then there’s me. In the middle of the battlefield. Trying to put an end to all of this nonsense with very few brothers and sisters in arms.
My goal is to make both armies understand that there are problems best solved with object oriented techniques and others best solved with functional ones. Most of the times a mix of the two.
That there are patterns best expressed through functional constructs and others effectively conveyed in a object oriented fashion.
War metaphors apart, there are real problems arising from this situation. And they directly affect you as a Software Developer.
Because by taking a side and looking down on the other you are missing multiple opportunities and neglecting a fundamental truth.
“Which opportunities am I missing?”
You are missing the opportunity to write better, more robust and expressive software.
You are missing the opportunity to grow your professional community.
You are missing the opportunity to leverage an immense flexibility that comes by combining the knowledge of both worlds.
You are missing the opportunity to cross-pollinate ideas and create new development patterns.
You are missing the opportunity to become a Top Software Developer*.
*Digression: I use Top and not Senior since nowadays the latter has lost any meaning. Developers with 3–5 years in the gig become Seniors by default, regardless of whether they can teach to Juniors, have the required discipline or act responsibly.
I also considered MacGyver Software Developer, but maybe it’s too much.
“Which fundamental truth am I neglecting?”
You are neglecting that programming languages are becoming evolved enough so that any attempt of categorization is fuzzy and unpractical.
Just think about the functional features you already use in your favorite OO language, maybe without even noticing it:
- Anonymous Functions
- Pattern Matching
- High Order Functions
- Lazy Evaluation
- Pure Functions
The complete list is longer.
There are great languages like Scala, Clojure and Swift that explicitly implement features from both paradigms.
Others, like Java, are quickly converging to the same point. Don’t believe me, believe the documentation.
Java 8, for example, introduced the Optional class. It’s a container that may hold a value of some type, or nothing. In other words, it’s a special case of a Monad, known in Haskell as the Maybe Monad.
You can now stop using null in Java.
You can now say goodbye to NullPointerExceptions.
And this thanks to Functional Programming features implemented an Object Oriented language.
After all, all that it takes to make a language functional is the support for functions as value types. Nothing more.
On the other side of the trenches, there are people expressing Object Oriented concepts using Haskell.
Classes and methods have been implemented in F#.
OCaml also supports Object Oriented Programming (the O stands for Objective).
Convergence is everywhere already.
Programming languages are becoming evolved enough so that any attempt of categorization is fuzzy and unpractical.
“Ok, I’m in. How do I start learning the other side?”
I come from an OOP background so I can share my experience on how I am doing it.
A lot of OOP features and patterns are useful when creating great software: composition, message passing, encapsulation, SOLID, polymorphism. The same concept of objects is so close to our real world mental model and hence so easy to grasp.
What I did in order to getting closer to Functional Programming was to look for things that were painful or fragile in OOP. Things I was not fully satisfied with.
I already mentioned the null “value”.
While coding in PHP, instead of iffing on the return value of, let’s say, a Repository, or throwing an exception in case of something not found, I return a Maybe and bind to it.
Yes, a Maybe. In PHP. Google it.
Same with my Service classes. Being my encapsulation endpoints for modules (someone would call them Aggregate Roots), I don’t want them to throw any internal exception.
What I want from them is a return value which is either a Success, optionally containing the command outcome, or an Error.
Very similar to the Either Monad.
Another example: Value Objects.
A Value Object is immutable.
It means you can’t change its internal value(s) after creating it. No setters allowed.
Immutability is another concept borrowed from Functional Programming.
After injecting one or more parameters into the constructor, there’s no way back. Your VO will remain the same no matter what until it gets disposed by the garbage collector.
Immutability brings two great advantages:
- Hassle-free Sharing
You can share any Value Object by reference because, being immutable, it won’t be modified in another part of the code.
This dramatically lowers accidental complexity and cognitive load required to avoid introducing any bug.
- Improved Semantics
Combine immutability with another rule: do not add any getter by default to your Value Object.
Your initial class definition should have a constructor and a bunch of private properties only.
This allows you to think about the transformation of your data at a later time. It means you can decide the semantics of your methods when you understand the exact use case(s) for your Value Object.
Doing so will improve your model by avoiding pointless interfaces and defining meaningful names and behavior for your Value Object.
Those were only three examples of how I combine both paradigms to achieve a more robust and expressive code.
I’m sure there are plenty of other examples for Object Oriented features used effectively in Functional Programming languages. Feel free to add some in the comments.
Make code, not war.
I hope you now understood why this diatribe is pointless.
I hope you will join the Caravan of Coding Love and start using both paradigms with the enthusiasm of a learner.
And I hope you will share your enthusiasm with other developers so that they also jump in.
It will be a better programming world for everyone.