1. Company history
I want to tell you a story that demonstrates how OOP helps fight with the complexity of large systems. This is necessary for you to understand the purpose of OOP.
Once upon a time there was a small company that provided intergalactic shipping services...
Let's call it Galaxy Rush. It employed 5 people. One worked in finance, the second worked in a warehouse, the third did the deliveries, the fourth handled advertising, and the fifth managed the whole enterprise.
They were very hard workers and succeeded at everything. The company had a good reputation and made a lot of money. But every year there were more and more orders, so the boss had to hire additional employees. Several more for the warehouse, several more for deliveries, one more for finance, and an additional advertising expert to expand the company's market share.
And that's when the problems started. There were more people, and they began to get in each other's way.
The marketer spends drains the bank account on a new advertising campaign, so there is no money to purchase products that urgently need to be shipped.
The warehouse has 10 brand-new hyper drives that get shipped to a client once a month. One courier flew in and took away a hyper drive for a different client, causing the regular order for 10 hyper drives to be delayed by a month. The first courier simply didn't know about the other order being filled by that the second courier.
The new assistant manager sends a courier away on a spaceship to purchase more goods. Meanwhile, everyone else waits for an available spaceship to appear. There are tons of urgent deliveries, but this assistant only oversees procurement and is trying to do her job well. The better an employee performs his duties, the more he interferes with the work of others.
Analyzing the situation, the boss realizes that important resources like the spaceship, cash and products are not being used optimally. Instead, they are subject to the rule "you snooze, you lose". Any employee could take a resource that everyone else needs for their work, thereby endangering the other employees and the company as a whole.
Something had to be done, so the boss decided to divide the monolithic company into a few departments. He created a shipping department, a marketing department, a procurement department, a finance department, and an inventory department. No longer could anyone simply take the spaceship. The head of the shipping department received all information about the deliveries and issued the ship to the courier with the most profitable order. Additionally, the warehouse didn't allow couriers to simply take any goods they wanted. Instead, picking products from the warehouse became a controlled process. The finance department wouldn't release funds for a marketing campaign if it knew that there would be a purchase soon. Each department had one public face — the department head. Each department's internal structure was its own business. If a courier wanted to get products, she went to the warehouse manager, not to the warehouse. If a new order came in, it was received by the head of the shipping department (
public-facing representative) and not by a courier (
someone not authorized to interact with the other departments).
In other words, the boss consolidated the resources and actions involving resources into groups (departments), and also forbade others to interfere with departments' internal structures. Interdepartmental interactions had to go through a specific person.
From the point of view of OOP, this is nothing more than dividing the program into objects. A monolithic program of methods and variables becomes a program comprised of objects. And the objects have variables and methods.
The problem was that any employee could work with any resource and give commands to any other employee, all without oversight or controls. We imposed a small restriction, but achieved more order. And we were also able to better control everything.
This is divide-and-conquer in its purest form.
2. How programs are created
I want to touch upon one more important point that reveals another advantage of OOP. Do you see that programs are more like animals than buildings? They are not built. They are grown. Development is constant change. In construction, you can have a good plan and follow it with precision. This is not the case with software development.
Very often in programming, you can't do something the way you originally intended and must rework a lot. Customer requirements change even more often.
But what if the customer provided a very precise specification? That makes things even worse. Take a look at what happens with the product over time.
The product's success will lead the customer to want to release a new version, and then another and another. And, of course, all you need to do is add "small changes" to the existing product. So you can see product development is a sequence of constant changes. Only the time scale is different. A new version can be released once a week, once a month or once every six months.
And what conclusion can we draw from all this? The product's internal structure needs to be maintained in a way that allows significant (and minor) changes to be made with minimal reworking.
But doing that is more difficult than deciding to do it. We already said that a program consists of objects that interact with each other. Let's draw all our program's objects on the board, representing them by points. And let's draw arrows from each object (point) to all the other objects (points) that it interacts with.
Now we'll combine the objects (points) into groups. Points should be grouped if the connections between them are much more intense than those with other points. If most of the arrows from a point go to others points in its own group, then the groups were formed correctly. We say that the points within a group have high cohesion while points in different groups have lower cohesion.
There is a "principle of loose coupling". A program is divided into several parts, which are often layers. The logic of these layers/parts is tightly coupled to their internal structure and very loosely coupled to other layers/parts. Interactions between layers are usually very regulated. One layer might refer to the second layer and use only a small subset of its classes. This is the principle of "dividing the company into departments" we saw earlier, but on a larger scale.
The result is that we can reorganize a department as needed to increase its effectiveness and we can hire even more people for the department, and as long as we don't change the protocol of interaction with our other departments, then all the changes made will remain local. Nobody has to relearn anything. You don't have to rework the entire system. Each department can do this kind of internal optimization if the mechanisms for interdepartmental interaction are well chosen.
Chosen well. But what if they are not chosen well? Then the capacity for change is quickly exhausted and you'll have to redo the entire system. This has to be done from time to time. You can't predict the future, but you can keep the number of redos to a minimum.
Principle of abstraction
Choosing how departments are structured and how they interact is the "principle of abstraction". In programming, it is used to determine best way to break a program into constituent parts and how those parts should interact. We can reapply the principle, dividing the resulting parts into parts, until we've broken the program down into individual classes.
Hiding the internal structure of these parts and strictly limiting interactions with other parts is encapsulation. Encapsulation and abstraction are cornerstones of OOP. A good program must follow these two principles. In the future, we will look at the rest of the principles and explore what benefits they provide.