Rethinking Object-Oriented Programming: An In-Depth Analysis
Written on
Chapter 1: The Flaws of OOP
Object-Oriented Programming (OOP) is often hailed as the pinnacle of software development. However, it paradoxically leads to significant waste in both time and resources.
The Misconception of OOP
Let’s start with a daring assertion: what is commonly recognized as OOP today is fundamentally flawed. To underscore this, we turn to Alan Kay, the visionary behind OOP:
"I coined the term Object-Oriented, and I can assure you I did not envision C++."
- Alan Kay, creator of Object-Oriented Programming.
The Roots in C++
Indeed, modern OOP traces its origins back to C++. However, C++ has never been a model of good design. Developed in 1979, it reflects a time when language designers were still honing their craft, leading to an overcomplicated amalgamation of features. OOP was merely the latest trend.
C++ incorporated superficial aspects of OOP—like inheritance and encapsulation—while neglecting Kay's fundamental concepts. So, what critical elements did C++ and its successors overlook?
Another insightful quote from Kay states:
"I regret that I long ago used the term 'objects' for this topic, as it leads many to focus on the less significant idea. The primary concept is messaging."
- Alan Kay, inventor of OOP.
C++ has methods, but these do not equate to messaging.
The Biological Analogy
Kay's background in biology influenced his vision for programming. He envisioned a system akin to biological cells, where each cell is autonomous and communicates exclusively via messages (such as neurotransmitters).
Kay successfully implemented his vision in Simula and subsequently in Smalltalk. In contrast, languages like C++, Java, C#, and TypeScript often pass references to objects as arguments, allowing them to share internal states. This leads to an environment where objects like garfield are stored within catManager, allowing direct access to one another’s internal workings—a scenario far removed from true biological independence.
The Dangers of Blurred Boundaries
Best practices in software development advocate for clear boundaries between modules. Yet, in the example above, the distinction between garfield and catManager becomes ambiguous, merging their states.
In languages such as C++, Java, C#, and TypeScript, this lack of effective messaging results in a convoluted program where the global state is pervasive. Instead of independent entities communicating through messages, we end up with nested dependencies, resulting in a chaotic structure.
Global state is widely regarded as a pitfall to avoid, yet it permeates modern OOP, which should similarly be approached with caution.
Concurrency Challenges
OOP emerged in an era dominated by single-core processing. Today’s multi-core environment renders OOP poorly suited to modern concurrency demands. The ubiquitous sharing of mutable state complicates parallel processing, leading to complex solutions such as thread locking and mutexes, which bring their own challenges like deadlocks and difficult debugging.
Java's Contributions
Java, while improving upon C++ with features like garbage collection and cross-platform compatibility, inherited the foundational flaws of OOP. Alan Kay lamented:
"Java is the most distressing thing to happen to computing since MS-DOS."
- Alan Kay, creator of Object-Oriented Programming.
Java's popularity further entrenched these flawed OOP concepts, paving the way for languages like C#, Ruby, and even JavaScript and Python to adopt OOP—often without justification.
The Consequences of Design Patterns
Now, let’s address the much-lauded OOP design patterns. Have you ever pondered why mastering OOP is so demanding? It necessitates extensive knowledge of various design patterns—often requiring years of mentorship to navigate effectively.
While OOP design patterns may seem beneficial, they essentially serve as stopgaps for the shortcomings of OOP. They represent an attempt to salvage an inherently flawed system. Imagine a poorly constructed project accumulating hacks, which are then labeled as design patterns.
Understanding Sunk Cost Fallacy
Consider this analogy: you purchase a concert ticket for $50, but on the day of the concert, a snowstorm hits, and you feel unwell. Despite knowing the drawbacks outweigh the benefits, you decide to go. This is the sunk cost fallacy—continuing to invest in something despite clear evidence that it's no longer wise.
OOP exemplifies this fallacy; individuals persist in investing in a broken system. Design patterns complicate code, making it less readable and maintainable.
Introducing an Alternative: Functional Programming
No critique of OOP is complete without proposing a viable alternative: Functional Programming (FP). FP addresses many of the inherent issues with OOP, such as complexity from shared mutable state and convoluted design patterns.
In FP, state is immutable, and the system promotes the use of pure functions that establish clear boundaries. With pure functions, the function itself becomes the boundary, allowing developers to focus solely on the task at hand.
Languages like Erlang and Elixir take inspiration from Kay’s OOP, utilizing independent processes that communicate through immutable messages, negating the need for intricate design patterns.
Functional Programming’s Simplicity
In FP, concepts like the factory pattern or dependency injection become superfluous. Instead, a simple function suffices to achieve similar outcomes without the burden of a "design pattern."
One critical aspect of FP is programming with immutable state, a fundamental property built into functional languages. This eliminates the need for cumbersome patterns and enforces a streamlined approach.
Mark Seemann, once a prominent figure in OOP, likened it to balancing a heavy ball atop a hill—a constant struggle against gravity. In contrast, FP allows the ball to roll effortlessly into a pit, leveraging gravity rather than resisting it.
Reversing the Damage
Many have noted that discussing Object-Oriented versus Functional Programming is a personal passion of mine. Why? OOP has wreaked havoc on the software industry, resulting in trillions of dollars in losses.
It is high time for the industry to embrace effective alternatives, promote education, and implement these solutions. The hallmark of quality software is simplicity—code that is both reliable and maintainable.
The next time you're tempted to reach for OOP design patterns, reflect on whether they're truly necessary. Perhaps it's time to abandon the sinking ship.
And, of course, please share this article, learn about Functional Programming, and teach others.
Thanks for reading!
Chapter 2: Video Insights on OOP
The first video titled "I Don't Like Object-Oriented Programming (OOP) 1/2" explores the critical viewpoints surrounding OOP and its flaws.
The second video, "Object-Oriented Programming is Bad," delves deeper into the pitfalls of OOP and advocates for exploring alternatives.