OOP Is Still Cool In 2021
Why is object-oriented programming still the best we have and how can it help us build well-designed microservices?
It is 2021, IT has already eaten almost the whole world and we have developed tools that make paradigms from the 60s such as OOP seriously outdated, right? Well, not really.
At least in the mainstream, object-oriented design offers the most beneficial approach for software development from code to system architecture. However, only when done right.
By merely using the keywords
class we do not create object-oriented code. One can easily write completely non-object-oriented code even in a pretty much object-oriented programming language like Java or C#, but only by employing the principles of OOP can we make our programs genuinely object-oriented.
Although these principles have been well-known for decades they are poorly understood by most developers even in 2021. More and more I see a constant shift to structural programming, a technique much older than OOP itself.
The result is sub-optimally designed systems that are hard to maintain, extend, and reason about. Error-prone, fragile, distributed monoliths are just one example familiar to many of us.
Knowledge acquired in school is a good foundation, but it is not sufficient. We have to focus on understanding rather than just knowing, we must learn principles over practices.
Principles of Object-Oriented Design and Programming
Alright, what are the most fundamental principles then?
An object is defined by its contract.
The contract of an object defines what the object can do, not how it does it. Looking at the object from the outside should not provide any insight into its implementation. The contract must not be violated; the object’s job is to protect its invariants. Business purpose is a solid base for a stable contract.
Objects are autonomous.
You should never ask an object to provide the information needed for a particular action. Rather, ask the object to perform the action for you. No object can do things to another object. Objects are active entities, they are not passive puppets.
All data is private.
Objects must hide all data and other details they need to work out a particular business problem. If data is not private, it becomes part of the contract. This is the difference between objects and data structures: objects are solid, data structures are transparent. More formally, we talk about the concepts of encapsulation and information hiding.
These principles may sound simple, but simplicity is often not an easy goal to achieve. Programmers tend toward “smart” solutions rather than simple ones; they, for instance, master OOP practices like encapsulation by using private attributes but violate the principle of information hiding by exposing them via getters and setters.
The list is, of course, not definitive, we can add many others such as composability, all SOLID principles, etc.
However, the three concepts mentioned are paramount, superior to all others, and most difficult to achieve at the same time. Therefore, they are often ignored completely.
Most importantly, they are universally useful on all levels of software development.
Nowadays, no technical post would be complete without mentioning microservices, an extremely popular architectural design pattern for building distributed systems.
How does object-oriented design apply in microservices architecture? First of all, let us recall the definition of a (micro)service:
A service is the technical authority for a specific business capability.
Now, what is a business capability? It is an expression of what business does and can do. Business capabilities are keys to define high-cohesive service boundaries.
It is a particular functionality that carries out a business capability. Functionality defines the system’s behavior.
A service is autonomous; its ability to function is not controlled or inhibited by other services.
Services are independent, self-contained, and free from external control and constraint. Services can decide on their own. The more autonomous our services are, the more loosely coupled they are.
Any piece of data or rule must be owned by only one service.
In other words, a service must encapsulate all data and implementation details it operates upon. We talk about a shared-nothing architecture in which every request is satisfied by a single node.
To summarize it in a few bullet points, a service:
- is defined by its capabilities,
- owns its data and rules,
- is fully in control.
Does this sound familiar? Sure it does! Conceptually, a service is just an object on the system level. Technical details differ, but the same ideas apply here.
Understanding principles of object-oriented design will help you build your microservices so that they are easy to maintain, highly cohesive and loosely coupled.
It is 2021 and we still don’t have a lucid understanding of how to develop our software. The IT industry grows rapidly and requirements change too quickly for us to catch up.
Five decades ago, great principles of object-oriented design and programming were defined and they can still teach us a lot today. We just have to learn and adopt them correctly.
Object-oriented design is a holistic approach. It can be successfully applied to the whole span of problems in software development.
All in all, the principles of object-oriented design and programming are the best we have. And this is not going to change any time soon.