For a non-developer person in the IT business, it’s crucial to know the fundamentals of each job involved. It’s good for a designer to know about writing, a good writer has to know design and everyone has to be aware of the pillars of development.
We’re talking theoretical knowledge just enough to appreciate the labor of each other and at least speak the same language when it comes to solving disputes. In this one, we’ll go through a specific yet general topic of object-oriented programming and what it means for non-techies.
Computers store massive amounts of data accessible within seconds. Using memory to store data is the main idea behind traditional or procedural development. It focuses on procedures and functions. Procedure is a sequence of instructions. A function is like a small assembly line that receives input data, does something with it and returns some result data. One input has one output:
For example, an email verification function. It receives some user input, checks it against some rules, and creates an output saying whether that email is correct or incorrect (true or false).
Procedures are helpful when a lot of commands need to be packed into one. You can check the email by doing a single command to see whether the input matches regular expressions or multiple commands like checking the dictionary, spam directories, and existing email bases. A function can pack a multitude of commands and actions and call them all in one move.
There’s a naming incoherence with procedures and functions. Because of the interference in functional languages, procedures became functions and functions with due complexity became procedures. Those are all entities of procedural programming so it does not matter because “the background behind those names has been washed out long ago”. – jpalecek on Stack Overflow.
What’s bad about procedural programming
Procedural programming works perfectly fine in simple programs where the majority of tasks can be solved by a handful of functions. Functions can be nested, interact between each other and process data from one function to another.
If you are building a “Register user” function, inside of it you need to check the email they put out. You call a “Check email” function inside the “Register user” function and depending on the function output, you either register a user or indicate an error and ask them to fix it. There can be multiple places where the same function is used. This makes functions intertwine.
Then a product manager shows up and says: “We should let the user know what the exact error is when entering the email”. Now we need the function to not just do true-false, but an error code as well. If there is a typo in the email address, it’s code 101, spam directory alert – code 102, etc.
It’s not hard to do. You just get inside the function and change its behavior: instead of the “true/false” output, it returns an error code or if there’s no error, says “OK”. And this is where the code breaks. All the places where the expected response was “true/false”, now get an “OK” and don’t understand it.
To fix that, we need to:
- Rewrite all the functions so that they would recognize new responses.
- Redo the checker to stay compatible with the old functions but capable of sending a response where necessary.
- Write a new checker for the new responses and use another checker for the old functions.
All of these can be done in an hour’s work. But imagine there are hundreds of functions and they change every day. Each change leads to a more complicated function’s behavior and result. Each change in one place affects three other places. You will have dozens of cloned functions and eventually, you will lose control over them.
This is what they call “spaghetti code” and this is why object-oriented programming was created.
Judging by the name, OOP is about some objects that run the entire programming process. It makes a lot of sense from a real-world perspective where everything is an object with a set of properties interacting with each other and changing because of that interaction. This natural vision was recreated in programming.
We had to abstract from the principles of how computers store and process information and learn how to build “virtual worlds” with distributed properties. This, however, made programming easier and more productive for the tasks that kept growing.
A team of developers is building a video game. A game is a system of characters and environment settings with a plethora of objects. Each character, weapon, tree, house is a digital object packing its properties and actions which change the object itself and the other objects as well.
Every developer can be working on their specific group of objects. It’s enough for them to have an agreement about how the objects’ interfaces are going to interact. If you are building a lawn, you don’t need to know how the cow that eats the grass gains weight. All you need to know is when the cow touches the grass’ hitbox, it reduces the amount of it.
The main difference between a traditional program and an object-oriented program is, the first is about the logic and sequence of actions in order to reach a goal. The second is a program as a system of interacting objects.
OOP simplifies code. An object is not a cosmic entity. It’s still a set of data and functions like in procedural development. Think of it as taking a piece of a program, putting it into a box and closing it. This sealed box is an object.
Developers agreed to call the data within the object properties and the functions – methods. Conceptually, those are traditional variables and functions. An object is like one of the kitchen appliances. The kettle boils water, the stove heats, the blender blends, etc. Inside every device is a bunch of different parts like engines, fuses, wires, chips, and modules but we don’t think about them when using a device. It just does what we expect it to do. All the devices working together are responsible for your dinner.
Encapsulation, abstraction, inheritance, polymorphism
These are the key concepts of OOP. They let developers make working methods and variables, then reuse them.
Encapsulation means the object is independent. Every object is set up in a way that the data it needs lives inside that object, not somewhere else in the program. For example, a “user” object contains all the data about them: their name, email, and whatever else. Also in it are the “check email” or “subscribe to newsletter” methods.
Abstraction means the object has an interface. The object has methods and properties that we can call from outside of this object. A blender has all the complicated mechanisms on the inside but only one button on the outside. That button is the abstract interface.
In a program, we can say “delete user”. In the OOP language, it’s “user.delete()” which means we are addressing the “user” object and calling the “delete” method. The coolest thing about it is we don’t care how exactly a user is deleted. We don’t need to think about this when calling.
For example, if two developers are building a shop, one is writing order module and the other, shipping. One has a “cancel” method in the “order” object. The other has to be able to cancel the order from the shipping screen. So they just write “order.cancel()”. It doesn’t matter how the other developer is going to implement the cancelation, which type of notices they will send, what’s going to be recorded to the database, etc.
Inheritance is the ability to make copies. This means developers can create a lot of objects in the image and likeness of another object. This way, they don’t have to copy and paste the code multiple times but to write it once and reuse it in the future.
For example, a perfect object called “User” stores all the possible information on what can happen to them. The properties can be name, age, email, credit card. The methods can be “Give discount”, “Check order”, “Find orders”, “Contact”. Based on this, you create a real user who will have all the properties and methods of a perfect user with extra ones if necessary.
Developers call these perfect objects, classes.
Polymorphism is a common language. In OOP, it’s super important that the objects speak a common language. If different objects have a “Delete” method, it has to do just that and have the same form everywhere. It can’t be “Delete” for one object and “Remove” for the other.
That said, inside the object, methods can be implemented in a variety of ways. For example, when deleting an item means showing a warning and labeling an item as deleted. Deleting a user means canceling their purchases, unsubscribing them from a list and archiving their order history. Those are all different events but to a developer, it don’t matter. For a developer, it’s just the “Delete()” method and they trust it.
With this approach, developers can build modules independently from other modules. The main thing is to elaborate on how these modules are going to interact. With this approach, they can enhance the work of one module without affecting others. The program itself does not care what’s inside of each block if the rules it works by remain the same.
Pros and cons of OOP
There are way more pros and that’s why the vast majority of modern developers use object-oriented programming.
- Visually, the code becomes cleaner and more readable. When everything is an object with its clear set of rules, we can figure out which object does what and what it consists of.
- Less similar code. In traditional programming, one function counts repeated symbols in a one-dimensional array and the other in a two-dimensional, the majority of their code will be identical. In OOP, this is solved by inheritance.
- Complicated programs take less to write. Every big program can be divided into several blocks, fill them with minimum viable, and then gradually saturate them with more functionality.
- Development speed increases. At the start, you can create the necessary components inside the program to get to the minimum viable prototype.
Now, the cons:
- Hard to understand and start. The OOP approach is more complicated than procedural programming; you are supposed to have a lot of theoretical knowledge before you even get to your first line of code.
- Needs more memory. In OOP, objects consist of data, interfaces, methods, etc. This needs more disk space than just a variable.
- Sometimes code performance can be compromised. Because of this approach, some things can be implemented trickier. That’s why an OOP program can work slower than a procedural one. However, with modern processors, this doesn’t bother anyone too much.