Object-Oriented Programming vs. Procedural Languages

Object-Oriented Programming vs. Procedural Languages
Photo by Sam Moghadam Khamseh / Unsplash

Object-oriented and procedural are two common programming language paradigms. Procedural programming languages include ALGOL, COBOL, BASIC, PASCAL, FORTRAN, and C, while a few well-known object-oriented languages include C#, Python, C++, Java, PHP, Scala, and Perl.

Procedural programming languages are very linear in nature. Let's think of it like this. You want to bake a cake mix.

  1. First, you preheat the oven.
  2. Then, you mix the ingredients for the cake in a certain order: first the dry ingredients, then the wet ones.
  3. Next, you pour the batter into a baking pan.
  4. After that, you place the pan into the oven.
  5. Finally, you allow the cake to bake for a specified amount of time, then remove it from the oven to cool.

Much like the steps of making a cake, in a procedural program, all the program's steps have to be executed in order. Now let's think about object-oriented programming (OOP). OOP has three main concepts:

  • Blueprints for objects called classes
  • Instances of the classes called objects
  • Applications or programs that manipulate or use the objects

It can be a challenge to master without experimentation, but for the sake of this post, let's go back to the cake example being made at a bakery rather than your kitchen. Instead of a simple todo-list, the bakery staff has devised a system to make baking cakes easy and fast.

  1. At this bakery, there are different types of cakes you might want to bake: a vanilla cake, a chocolate cake, a carrot cake, etc. Each of these types of cakes can be considered a "class." They all share certain characteristics that they inherit from a Cake class (they all need to be baked, they all require some form of flour, sugar, eggs, etc.), but each also has unique attributes (vanilla cake uses vanilla extract, chocolate cake uses cocoa, etc.).
  2. When you decide to bake a specific cake, say a chocolate cake, you're creating an "object" or an "instance" of the chocolate cake class, which extends the Cake class. This specific cake that you're baking will have all the attributes of a chocolate cake, but also inherits from the Cake class that it extends.
  3. When you're running a bakery, you also have other classes of objects that interact with the cakes. For instance, you might have an "Oven" class, which can accept any cake, because all cakes share the "Bakeable" characteristic. You can create specific Oven instances, like a convection oven or a traditional oven, each with its own attributes and methods.
  4. You can even have a "Baker" class. The Baker objects have methods like "MixIngredients" or "DecorateCake." These methods can be used on any cake object, because again, all cakes share certain characteristics.

As you can see, this gets complicated super fast, but most computer programming projects are very complicated. Many new programmers will use scripting languages that allow the use of procedural-style programming, and that's fine for simple programs, but as your project's complexity scales, so does your program's complexity. One of the best use cases for OOP is when you're trying to simulate real-world ideas, things, and concepts on a computer. Even though OOP typically results in more boilerplate code, it makes it easier long term and allows programmers to better organize their code. Verbosity and specificity are a programmer's best friends.

How can OOP be used in the real world?

OOP emphasizes reusability, encapsulation, and inheritance making OOP a compelling choice for managing complex coding projects.

Never repeating yourself is a great rule to live by when coding. In some cases, it would seem that simply creating methods/functions would provide the same benefit of reusability as classes/objects. However, I think the true superpower of an object is being able to store state within the object's attributes.

A few months ago, I had a project where I needed to perform an ETL (extract transform load) process where, at a high level, I imported an export from Stripe (a payment processor), added some data from a Stripe API endpoint, and then exported the data into a format that another payment processor could import. This had to be custom because no other solutions existed, and some of the Stripe data was only accessible through their API, not their exports, likely in an attempt to lock you in. The way I did it was to create a class for the items I was processing that stored all of the item's data in attributes using the constructor. I then added methods that could be called to interact with the data using the data stored in the object's attributes. The benefit is that I could call objectt1.doThingy() without having to worry about making sure I'm passing in the right parameters. Because I have an instance of my class called object1, all I have to do is call the method, and the method knows where to get the correct data.