Re-evaluating core OOP concepts
If we want to be open and have a critical look at OOP we have to first define the core values that actually matter to keep up implementation effectiveness, maintainability, extendability and code reuse. Why should we care about implementation effectiveness, maintainability, extendability and code reuse? Because if we score badly in this fields, our software will inevitably be more expensive (time-wise and money-wise) to write, maintain and extend.
Core values concerning architecture, design and programming
3-VALUES MODEL
- Expressive problem solving
- Simplicity of abstractions
- Easy reasoning about code
Why should we care about no. 1 “Expressive problem solving”? Expressive means “effectively conveying a specified quality or idea”. So this goes down to the fundamentals of programming: turning ideas into something that can be understood by a computer for the purpose of solving a real world problem.
Why should we care about no. 2 “Simplicity of abstractions”? Abstraction is the way of dealing with something that only exists as an idea. This too goes down to the fundamentals of programming. It’s about the “how” in which ideas are dealt with and that this how should be guided by the goal of simplicity.
Why should we care about no. 3 “Easy reasoning about code”? Because without the capability to reason easily about code, we could not convey the idea of the problem solution effectively and we did not deal appropriately with this idea. We did not go strongly enough in the direction of pursuit for simplicity.
1-VALUE MODEL
- Pursuing simplicity
Lets have a look how the core concepts of OOP perform in the light of simplicity.
Foundation
The foundation for any kind of programming are variables (names that can hold values) and functions (expressions that do something with those variables), also called procedures. Additionally many programming systems support some kind of module system from the start, or one was added later on.
Classes and objects/instances
Classes are the fundamental building block in object oriented programming. A class is a way to merge variables and functions together into a unit. This unit can then be handled as one and be expressed as a variable somewhere else. Also one can produce many different of a kind, which are then called objects or instances. The production process is called instantiation.
Encapsulation
Based on classes and objects, encapsulation gives us guidelines about how to merge variables and functions. Only functions and variables that belong together should be merged this way. In fact it’s a constant cause for controversy among software architects and programmers as to how exactly this is performed. Usually most of the solutions are arbitrary.
Composition, inheritance, and delegation
The concept “inheritance” especially has an interesting past. In the beginning of Java it was celebrated as the most important concept for code organization and software architecture. It’s used to distribute “traits” of a “family” of classes and objects over several “generations”, so that a complex hierarchy of “things” is created. A so called type hierarchy. The time spent for building such things had been greatly exaggerated over the last decades, especially when measured by the value added at the end of the day.
The two other related concepts composition and delegation where not originally counted as object oriented virtues. They actually come from somewhere completely different. They where adapted by the object oriented community to address the problems caused by trying to use inheritance for everything.
Polymorphism
Also called subtyping in times when inheritance was still celebrated. It basically means that different types can implement the same functions so that they can be handled in the same way. One of the examples that is given quite often is a drawing system in which circles and rectangles both have a “draw” function (also called method), so that both can be handled the same way by the drawing system. One could rephrase as: both being handled as something “drawable”.
Polymorphism/subtyping and inheritance both are questionable concepts. Inheritance especially did cause more harm than good in the pursuit of simplicity. Thankfully they can easily be navigated in a less harmful way.
The OOP mental model
Object orientation represents a mental model and was considered the one and only “serious programming” up until recently. While the thing doesn’t appear to be too complex from a distance, it convolutes the problem space quite quickly with unnecessary complexity. Some programming environments (like Java did) and many organizational programming guidelines still enforce this mental model.
What this means is that every problem needs to be expressed as classes and objects. Every single one of them. And that’s where the concepts really falls apart, because this enforcement denies the technical nature of computation:
The technical nature of computation
- To transform data between representations and in the form of algorithms.
- To express data appropriately so that transformations can be applied to it.
Let’s remember the goal of Alan Kay:
- I wanted to get rid of data. […] I realized that the cell/whole-computer metaphor would get rid of data […]
Alan Kay in a response to a question from Stefan Ram Source: Re: Clarification of “object-oriented”
To get rid of data was the honorable goal. What classes and objects actually turned out to be used for mainly, was to construct data type hierarchies. Those turn every kind of problem into a tree of interdependent, nested data types. So instead of getting rid of data, classes and objects turn everything into a problem of hierarchically structuring data. Usually in a way that is not accommodating data transformation because the object oriented mental model does not put the practitioners into a mental place where they’re specially well equipped to do so.
So what is actually required is the transformation of data and the appropriate representation of data to effectively apply those transformations. Inheritance enforces a mental model where most of the time is spent pressing data into arbitrary hierarchies and merging it quite arbitrarily with transformations. OOP additionally complicates expressing processes, because the notion of a process that has a clearly designed beginning state and a clearly designed end state, not to mention preliminary states in between, causes an explosion of required effort: Built on top of OOP this kind of thing becomes magnitudes more complex to build, maintain and reason about than under a non-OOP mental model.
Coming back to Alan Kays honorable goal and re-evaluating what we achieved with OOP over the decades, we should be honest and conclude, that the promises where not met: We cannot get rid of data. We cannot lift our reasoning-space above actual existing problems as long as computing power remains restricted by power efficiency. That the OOP mental model poses a huge overhead of mental exercise that is mostly unnecessary to solve the inherent technical problems of data transformation. For practitioners of object orientation, what should be the main concern, therefore is actually taking a back seat.
This path astray is further intensified by one aspect of this mental model which is called “The kingdom of nouns”. It encourages to think about the problem by objectifying everything.
Being forced to skew the solution finding process by building over-complicated data hierarchies and objectifying everything, does not make it more expressive. It actually encumbers transformation-focused reasoning about the problem.
Software design patterns
Programmers that used object orientation over time experienced repeating patterns occurring. Abstract combinations of classes and objects to solve similar technical problems. Here’s a list of some of them:
- Adapter, Wrapper, or Translator
- Bridge
- Composite
- Decorator
- Extension object
- Facade
- Flyweight
- Front controller
- Marker
- Module
- Proxy
- Twin
- Chain of responsibility
- Command
- Interpreter
- Iterator
- Mediator
- Memento
- Null object
- Observer or Publish/subscribe
- Servant
- Specification
- State
- Strategy
- Template method
- Visitor
Many of this patterns are only necessary because the problem is reasoned about in the object oriented mental model: Considerable added complexity caused by thinking in object oriented fashion. Especially when it comes to maintainability, object orientation cannot deliver on his promises.
Where is the evidence?
Let’s revisit our initially mentioned core values:
- Expressive problem solving
- Simplicity of abstractions
- Easy reasoning about code
There has never been evidence that object orientation adds something in those fields in comparison to the alternatives. Pure object orientation turned out to be a factor for over-complication of software systems, proven countless times over the last decades. In fact if object orientation as a hard design goal is given up, expressiveness of problem solving, simplicity of abstractions as well as the ease to reason about code raises considerable. That contrary evidence should be enough to recognize “pure object orientation” as what actually became of it:
OOP IS A DOGMA
OOP leads to Rube Goldberg machines
If you don’t know what a Rube Goldberg machine ist, here’s what Wikipedia is saying about it, plus an example:
A Rube Goldberg machine, named after American cartoonist Rube Goldberg, is a machine intentionally designed to perform a simple task in an indirect and overly complicated way. Usually, these machines consist of a series of simple unrelated devices; the action of each triggers the initiation of the next, eventually resulting in achieving a stated goal.
Professor Butts and the Self-Operating Napkin (1931). Soup spoon (A) is raised to mouth, pulling string (B) and thereby jerking ladle (C), which throws cracker (D) past toucan (E). Toucan jumps after cracker and perch (F) tilts, upsetting seeds (G) into pail (H). Extra weight in pail pulls cord (I), which opens and ignites lighter (J), setting off skyrocket (K), which causes sickle (L) to cut string (M), allowing pendulum with attached napkin to swing back and forth, thereby wiping chin.
Often the first impression a software programmer or architect has, when joining in on an existing object oriented project, is somewhat funny. Especially when it’s a big project the resemblance to a Rube Goldberg machine is usually quite uncanny.
In the next article I want to show which kind of concepts can be used to actively invest in simplicity by not doing everything in an object oriented way.