Let’s OOP from scratch
So, you landed on this page with some OOP (Object Oriented Programming) knowledge, and want to get more of it. Right?
In this article, I would like to provide how you can exercise your OOP skill from scratch.
A simple program without too much restriction (or better, convention) will encounter some of OOP pattern problems, and I will try to provide some insight on when to think about them.
Think outside of frameworks
If you’ve done some web app development, you’re probably already familiar with a web dev framework of some kind.
In today’s programming languages, it’s critical to adapt web conventions. Rails flourished in a way that it brought MVC pattern so incorporated into its framework, that people can just start a new project and grow it in a way the pattern forces you to follow.
That’s great, until you realize there’s more to it. If you want to make architectural decisions during the development of the product, you’ll need to think outside of the box the framework has given to you.
How to learn OOP from scratch
One way to do it is to write your own web framework. If you’ve read enough code in that language, you’ve probably become fluent enough to be able to read the code of some smaller web framework libraries. In Ruby, a lot of people grab Sinatra and gem unpack it to understand how it’s abstracting a request/response cycle.
And another way, which I’m about to try, is to build a simple script that you start from scratch, and observe when the codebase gets entangled.
This approach will not only make you aware of the common design patterns, but also embeds its knowledge into your context. When you embody knowledge that ties with your own experience, you remember better. It survives the time of generalization, and you will be comfortable applying that pattern into some of your future projects.
So here we go.
I suggest you to use a language that you’re most comfortable with (so that you don’t reach out for libraries that do heavy-lifting for you). Also, the code you’re about to write should satisfy following two criteria.
- It should be small enough, so that you can finish the first iteration within one slot of your time (e.g. 2 hours after work, or half a day on weekends)
- You’re passionate about the field so that it’s easy for you to come up with feature requests by yourself.
In my case, because I have a passion for game programming, I came up with a simple console-based simulation game with Ruby.
A. First, find out the domain of your code
Code is being defined in its domain; the domain defines its overall structure regardless of the details.
In my case, I’m building a game. A game is, in its ultimate abstraction, a series of inputs and outputs that both changes upon each other.
When a new input arrives, an output differs. When output is being transferred to the player, she provides new input in order to get closer to the goal: winning the game. So, often times, the game template starts with laying down a “main” loop representing one game cycle, and within the loop accepts inputs and commands outputs.
B. Next, spot the outermost entity in its domain
Now that you have an overall structure of your code in your mind, it’s time to prioritize which entity you should first implement. Because objects are essentially defined by the messages it sends and receives, it’s always a good idea to start from outermost entity to the outside world.
OOP encapsulates implementation, only exposing interfaces that can receive certain messages. So, the outermost entity that interacts with the world you don’t control is the first priority. In the example of game programming, I would define the players (that emits inputs) the outermost entity.
Players are the look and feel of this domain (game), thus should bridge the game world and the outside world. This is the contract we have to secure all the time, not matter how much you change your implementations.
C. Write the interfaces, let them force you to write a series of chain-reacting methods
This outermost entity with a set of interfaces will most certainly make you write more code, across different part of your code. It forces you to derive a certain implementation that will achieve the change; thus a chain reaction.
So in my case, after following what the outmost interface required me to implement, the code expanded into a few classes with each class having ~ 100 lines of code.
At this point, you’re pretty comfortable navigating the code you’ve expanded into. Everything is where you remembered them to be, each method/class is small enough to be comprehensive. Plus, its level of abstraction is not confusing, and most importantly, you’re confident future change is dealt with not that much of difficulty.
“fail purposefully” by requesting a feature request yourself
Then in next iteration, it’s a perfect timing to “complicate” your program with a feature request by yourself. Because you’re a business owner in this case, you’re free to come up with anything interesting to you.
In my case, I tried to add a complicated interaction between game players. It ended up in one of the ugliest code I could possibly write.
But don’t worry. That’s the intension. If your feature request is complicated enough to stretch yourself, you inevitably mess up the codebase. It’s either the first abstraction you took was immature or the added code wasn’t following the grand design. Being aware of this distinction already teaches you valuable things.
This is also the perfect timing to look for “established solutions” from the books. Because you have dirty code in your hand, you are more eager to learn about solutions than just skimming through textbooks.
In this article, I introduced a way to familiarize yourself with OOP by starting small, and grow gradually. I like this approach because the hard-earned experience don’t go away easily; it’s worth the struggle.
Remember, you should maximize your learning opportunity. Stop often, don’t rush. After all, it’s a toy project without any deadline. This is the time to sharpen your skill, and it will help you when you struggle in the real project at your workplace.
Hope this inspires learners of OOP!