Architecture | Object-Oriented vs Functional Programming (And Why the Argument Is Wrong)

Every few years, the OO vs Functional Programming debate resurfaces, usually framed as a zero-sum argument. One side claims objects are just mutable state wrapped in ceremony. The other dismisses functional programming as academic, unreadable, and detached from real-world systems. I’ve worked with both styles for over two decades across finance, energy, retail, betting, and government systems, and the longer I do this job, the clearer it becomes: this argument is based on a misunderstanding of what OO and FP actually are.

Let’s clear that up.

Object Orientation Is Not About State

One of the most persistent myths is that object-oriented programming is fundamentally about managing mutable state. It isn’t.

Objects are not data structures. Objects may use data structures internally, but those details are deliberately hidden. This is why fields are private. From the outside, you cannot see state at all—you can only see behaviour.

An object is best understood as a bag of functions, not a bag of data.

When objects are treated primarily as data holders—especially when exposed directly via getters and setters—that’s not good OO, it’s a design smell. This confusion is why tools like ORMs muddy the waters. They don’t map relational data to objects; they map relational data to data structures that merely look like objects.

Good OO keeps data hidden and exposes intention through behaviour.

Functional Programming Is Also About Functions Operating on Data

Functional Programming doesn’t escape this reality either. Every functional program ever written is composed of functions that operate on data. So is every OO program.

It’s common to hear OO described as data and functions bound together, but that’s true of all programs. The real difference is not that functions and data are bound—it’s how much discipline is imposed on changing them.

At that level, OO and FP are not opposites at all.

The Real Differences

The meaningful differences between OO and FP come down to what each style restricts.

Functional Programming Imposes Discipline on Assignment

A true functional language does not allow assignment. You cannot change the value of a variable once it is defined. Mutation is either impossible or heavily constrained behind explicit ceremony.

This has profound consequences:

Most functional languages do allow mutation eventually—but only after you’ve jumped through deliberate hoops. And because of that friction, most code simply doesn’t mutate state at all.

That’s not an accident. That’s the point.

Object Orientation Imposes Discipline on Function Pointers

OO’s real contribution is polymorphism.

Polymorphism is implemented with function pointers. In low-level languages, managing those pointers manually is painful and error-prone. Object-oriented languages do this work for you. They initialise them, marshal them, and invoke them safely.

In languages like Java, every method call is polymorphic. Every call is an indirect call through a function reference.

This is what OO really gives you: safe, ubiquitous polymorphism without manual pointer management.

These Disciplines Are Not Mutually Exclusive

FP restricts assignment. OO restricts how functions are referenced and invoked. These concerns are orthogonal.

There is nothing preventing a system from imposing both disciplines. You can write object-oriented functional code, and when done well, it’s extremely powerful.

Why Polymorphism Actually Matters

Polymorphism inverts source-code dependencies.

At runtime, a caller still depends on the callee. But at compile time, both depend on an abstraction. This inversion allows implementations to be swapped without touching core business logic.

This is the foundation of plugin architectures, hexagonal architecture, and dependency inversion.

Why Immutability Actually Matters

The benefit of restricting assignment is simple: you cannot corrupt shared state if you never mutate it.

Functional-style immutability dramatically reduces race conditions, concurrency bugs, and temporal coupling—critical properties in modern multi-core systems.

Design Principles Still Apply

Choosing FP does not make design principles optional. Choosing OO does not make them automatic.

Good design is independent of paradigm.

Final Thoughts

OO is good when you understand what it actually is. FP is good when you understand what it actually is. Combining them thoughtfully is often better than treating either as dogma.

If you’re still arguing OO vs FP, you’re arguing the wrong thing.

Object-oriented analysis and design Functional programming