-- (Even if you don't read this whole comment, I urge you to watch this fantastic video which illustrates procedural, OOP(lite), and FP approaches to a sample problem: https://www.youtube.com/watch?v=vK1DazRK_a0 (Despite the name, it illustrates JavaScript, not Clojure). If you follow this approach, you don't even have to tell people you are doing FP. You'll just end up with better, more understandable, and more easily testable code.) --

The early (early as in C++ days) benefit of OOP was probably that it made programmers stop and plan before coding.

Having learned FP 20 years after learning OOP, I feel certain that I can do the same things in less and more understandable (and MUCH more easily testable) code in FP.

OOP was awesome for a small set of cases and for academic scenarios. But like REST, it doesn't map well to all needs. Then it becomes awkward and unnecessarily complicated.

FP, or simplified as immutable data transformations with necessary mutations pushed to the edges, works everywhere, all the time. In FP you can still choose to model your data in hierarchies, keeping some of the useful bits of OOP. But it's still data in, results out.

Until you've spent time on real projects in both, you cannot appreciate why FP is superior.

(And to be clear, I'm not even talking about Haskell and type-obsessed FP. Perhaps because I'm not a Haskell guy, I can't appreciate it. But it smells to me like an extreme of a good thing (and therefore not usually the best thing for the situation); but I digress.)

Concretely, I worked recently for a client that needed Ruby on Rails development done on a production product. It was fairly OOPish (in the Ruby way, which is to say much less insane than Java from the past OOP). Even so, the OOP at the business logic level was unnecessary. Testing was complicated and full of code to mock and fake.

When we were given the task to build a completely new solution to the same problem, greenfield, I immediately began building modules with almost entirely pure functions. Because Ruby isn't designed for this approach, it does involve a bit of care to respect memory and object copy time costs. But in many business cases, the volume of data being processed isn't significant or isn't fast-repetative.

The new product had many fewer lines of code, and the test cases were as close to beautiful as maybe is possible for tests. That's a different subject for debate...

The less experienced devs took a bit of time to accept and adjust, but the mid-level engineers became big fans of the approach. The juniors just accepted it (so nice :D). Test coverage went up, and the cost of adding new features went way down.

My FP languages of choice are Clojure and Elixir in that order. Elixir does offer some pretty great features that Clojure doesn't have (extensive pattern matching), but the syntax is imo very noisy compared to the utter simplicity of s-expressions. Either is fine for me. Ruby is fine, with some care. Python too. Vanilla Javascript can be fine, and some libraries can improve this.

Anyone who has read this far and is not convinced, I urge you to follow some Elixir tutorials and reach the point of grokking it. Then if you're a web dev, Phoenix is a fantastic framework. Also, the Erlang (BEAM) VM provides so many useful structures and utilities to allow you to build big distributed things easily compared to other languages.

Be warned though: once you do this, you will forever be frustrated by OOP codebases.