Object oriented programming has been the de-facto programming methodology since they day I learnt that there is something called computer programming. Several of the most popular programming languages are primarily object oriented programming languages. The most commonly asked interview questions for programmers are about object oriented programming.
Until, functional programming just blew up a few years ago. Functional programming languages have been there since the 1960s mind you, but only a few years ago they gained traction among ‘commercial’ developers. I found a ton of people learning Scala and lambdas and observables and all the associated jargon. A group of us jumping ships and embracing functional programming as the way to go for all our new projects. And another group of us sticking to the familiar grounds that is object oriented programming.
So far I’ve done two projects in the functional programming style, both web applications. One in Scala and one in Java (Spring Reactor). Here’s what I’ve learnt so far as contrasts between Object Oriented Programming and Functional Programming.
The first difference that we need to appreciate is the core principle guiding these methodologies. Whenever I see coders struggling to adopt functional programming, it is because they don’t have a grasp of this.
- In object oriented programming, we think of everything as objects with state. The flow of the application is dictated by change in state of the objects involved.
- In functional programming, we think of everything as operations. The flow of the application is dictated by the chain of operations.
If you are like most other programmers, you would have learnt a bunch of design patterns to apply in your projects. And I bet many of them are not just ‘design patterns’, they are ‘object oriented programming design patterns’. You need to even unlearn many of these. If you try to apply these common design patterns when you do functional programming, it will be like hammering a square peg in a round hole.
For the last couple decades or so, object oriented programming has overshadowed all the other ways of programming and this has one bad side effect – so much of the learning material depends on real world analogies. We’ve all come across things like the
Animal --> Dog --> Dalmatian kind of analogies right? Well you need to forget all that and realise that abstractions are only there to lighten the cognitive load.
Computer doesn’t do dogs and cats. Computers do sets of operations on very basic units of data. Data like bits and bytes. Functional programming relates more to this attitude in a programmer. You are not working with simulated models of objects. You are taking an input, doing some processing and giving an output. Try to apply that to any programming task that you do. For example, a web service, takes a request as an input, does its processing stuff, and then sends a response as an output. This can be broken down into several levels to achieve cognitive ease, by breaking down the processing into multiple functions, and then chaining them by giving the output of one function as the input to the next function.
Choosing between the Two
It is not simple to classify an application, because most applications fall into multiple categories for purposes like these. Think about the core purpose of your application and make your decision based on that.
- Object oriented programming is preferable when you are representing a world of objects. For example a simulator, or a video game.
- Functional programming works well in scenarios where your application is a processing pipeline. For example a event stream processor or a data processing API.
When you are trying to choose between the two, do not think of peripheral activities like logging, IO (even database updates). Rather, think of the main purpose your application is solving for its user. Is it giving your user an object-state model that they can manipulate? Or is it providing an engine that transforms their input and gives them an output?
Combining the Two
In real world, you probably are going to combine the two programming paradigms, rather than use strictly only one. Functional programming seems like a good fit for a web service, but some of the components are still better represented by an object oriented model. We can think of the web service as a series of functions that, in the beginning take in a request, and in the end emit a response. But entities like
repository can still stay as objects. In fact, a
pure function will not have side effects, but this is hardly useful in the real world right? We need to almost always have side effects – update a database, write to a log file, send out an email and so on.
The most visible differences between the two programming methods is when you look at the code. Some important differences are –
- Objects are the core entities. The program flow is usually instantiating objects and modifying their states. Any processing that is done, is as a means to change some state.
- Control flow in object oriented programs is done through simple and traditional constructs like loops and if-else blocks.
- There is a global scope, then there is a session scope, then there is a thread scope. Or simply put, there is always some global state from where you can get your environment variables from. The ‘context’ (that holds things like current user, configuration parameters etc) are available from their respective scopes.
- Concepts like threads and concurrency are handled by the application code. Even if you use a multi-threading friendly framework, you still might have to declare what is thread-safe and so on.
Functions are things. You create functions and assemble them in chains. You can assign functions to variables and pass them as arguments to other functions.
- Control flow in functional programming is done by chaining, filtering and recursion. Streams are preferred to collections.
- There is only a local scope. In functional programming, the best practice is to provide everything your function needs as arguments. The ‘context’ (that holds things like current user, configuration parameters etc) gets passed in as an argument to all functions that need it.
- Since a ‘global state’ is not even assumed, programs are by default thread safe. And most functional programming platforms manage concurrency by themselves, upon this same assumption.
To put in a simple way, when you are doing functional programming, don’t think of objects and types – rather, think that you are making a lot of small black boxes. Each one takes an input and gives an output. And then you’re arranging all those black boxes to make a useful application. If you can grasp this, you’re probably going to have a very easy time settling into functional programming.