Michael Feathers, the author of Working with Legacy Code, described in a neat way the difference between object and functional oriented programming:
OO makes code understandable by encapsulating moving parts. FP makes code understandable by minimizing moving parts.
Moving parts refers to those elements of an application that are stateful and change constantly. State management in any application is a complex task. Connections between parts are described by relations which must satisfy rules imposed by the domain. Adding a new element to such a complex system needs to be done carefully, not breaking any existing relations. A programmer must first understand the domain, learn about components and relations between them before touching any code. This process is long and does not always guarantee that the change you make will work correctly.
Object oriented programming deals with system complexity by encapsulating components into so-called capsules, which hide implementation details, exposing an interface through which the interaction takes place. The responsibility of state management is routed to the components. Each component should be responsible for changing its state in a consistent manner. Objects can be treated as black boxes with inputs and outputs and building system is like making a construction from blocks. The smallest unit of code sharing is a class. Code sharing can be done by composition and inheritance. Those techniques dramatically simplify the inference of whether the program is correct and makes the code easier to understand by another programmer.
Functional programming approaches the problem of state management in a completely different way. It tries to minimize those parts of the system that are moving. The code is divided into two parts. First part deals only with pure values and has no side effects, it doesn’t introduce any change in application state. The second part often called interpreter deals with side effects. As we write the code, we create expressions that take a form of constants and functions. In a purely functional approach functions always return values and have no side effects. This implies that calling a function multiple times with the same arguments will give the same value each time. It greatly simplify the inference for correctness and makes functions composable. However, without side effects application can’t interact with the outside world. So how the functional approach deals with side effects ? How to read files or print something to the console? In a functional world reading a file is an action and an action is just a pure value. Actions can be executed, but the process of running a given action is done by an interpreter. During running an action side effects take place. We can think of an action like of some kind of recipe which describes what needs to be done. This recipe is just a pure value so function which returns it is pure and everyone is happy.
Why bother with functional programming ?
One can ask if I know object oriented paradigm why to even bother with functional programming ? An object oriented programming is a silver bullet. Isn’t it ? Well, it turns out not. When a program is getting bigger and bigger it is very hard to keep the complex implicit state in check even if the code is structured in well-formed modules. Even if an abstraction is given, some parts of the program need to know about their implementations. It abuses the assumption that the component behavior should be rather defined by an interface than by implementation. As an example let’s assume that there are two components
componentB and two resources
componentA locks two resources
res2, when a method
a is called. For
componentB when a method
b is called, two resources are also being locked but in different order so first
res2 and then
res1. After calling
b respectively on
compomentB in parallel in some circumstances we will observe a deadlock. To fix this issue we need to look at the implementation of these two components and change the resource locking order in one.
As you see, for parallel processing object oriented programming doesn’t feet well. Many issues arise when we want to spawn some threads do some work and then aggregate the result. Functional programming is a rescue. However, we aren’t forced to change our favorite language to deal with functional programming. Many of the concepts and idioms can be implemented almost in every language like: immutability, pure functions, total function and so on.
How to start with functional programming ?
In my opinion the best way to begin, is just to start using some core functional concept in your favorite programming language. Try to keep your data structure immutable. Instead of throwing exceptions try to encode errors in return type of the function using monad either or option. Write mostly pure, referentially transparent functions. Over the time when you gain more experience you will discover that you need more expressiveness, and this can be a signal to switch to functional language.
In a functional world there are a lot of buzzwords which are used extensively by programmers. Getting them known is a good starting point of learning functional programming concepts.
higher order function,
algebraic data type (adt),
persistent data structures,
call by name,
call by value,