“Learning from others’ mistakes helps us grow without wasting time.”
I can not agree more with this.
This is my first technical article, after one and a half years working in the Data industry. I’m a beginner in Python, trying to become as pythonic as possible.
This post is to reflect on what I did and to some extent help other beginners like me avoid those naive mistakes that I made when applying OOP (Object Oriented Programming) concept to my API reporting.
A brief definition of OOP, it’s “a programming paradigm which provides a means of structuring programs so that properties and behaviors are bundled into individual objects” following to realpython.com.
To me, the most important value of OOP is its power to encapsulate everything having the same behaviors into a single class, helping us obey the most basic rule for developers: DRY — Don’t repeat yourself.
That’s also the main reason we (I mean my team) decided to modularize many separate API reporting functions and encapsulate them into one Base class. The objective is clear, we want to simplify our code, make it more elegant and reusable.
Imagine when we buy something online, sometimes, the moment the goods arrive is also when reality hits us so bad. When I finished my first Python class, I got disappointed because what I created is such a mess.
It doesn’t help simplify the code, it even makes the codebase more difficult to debug, more open to errors, and its reusability is not as good as I expected. Here is why:
1. Everything is modularized including rare cases.
OOP is about finding patterns in the code and modularizing them for better reusability and succinctness, but not everything should be put into those patterns. I was too ambitious (or naive) trying to fit every single thing into 1 single class which increases the code complexity.
Eg: The reporting file I get from multiple sources mostly in the JSON format. Then there is source A that returns me the csv file which I cannot apply the same “extracting_file” method to get data from the file as what I did to JSON. And my solution was creating a new file_type variable then use if JSON then does this, elif csv then do that.
This is not recommended at all because it makes our code unnecessarily lengthy and less pythonic. The recommended way to solve this is creating a function in the source A derived class that overrides the extracting_file in the base class to get data from the csv file. The if statement is also my second point.
2. Too many nested if statements — a sign of poor design.
Nested if statements is like:
The nested if statements break the flow into small pieces, making the code extremely poorly readable and maintainable.
3. Exploiting global variables.
This is one of the most severe mistakes that I made, also I found it too tempting to resist.
Global variables are the privilege of OOP. It’s like the EU, without borders, you can go everywhere with so little effort.
To me, the self keyword is real-life magic. I wondered why do we need to create a parameter within a function while we can create a global variable and bring it to anywhere we want. I was so wrong.
Global variables are like fast food, it’s convenient and harmful at the same time. Defining everything as a global variable makes it extremely difficult to debug and make the code much more open to errors.
Instead of only care about what a function will do, we need to think about which global variables it will change and how that affects other functions and our output, especially when our class contains many methods leading to a huge collection of bugs we can spend the whole life to fix :laughwithtears:. My fourth mistake is also related to the method in a class.
4. One method handles too much work.
They said that if a function takes more than 4 parameters, the function is doing too much. We should split it into smaller functions improving the readability of our codebase. I used to find it useless splitting the functions but I changed my mind.
Small functions are more beneficial because:
- It’s much easier to understand due to containing a few parameters that our brain can handle (there are some researches about our brain limit said that we can only focus at most 4 things at once).
- It’s easier for us to reuse a function doing a single task rather than a customized function doing more than what we actually need which may throw us a bunch of bugs.
5. The final and the most harmful one: lazy or scared to explore.
When we have a task to do, especially with a deadline, it’s always tempting to apply what we already comprehend to get things done in the fastest and least effort way rather than searching for new optimal solutions.
But that available knowledge will soon become obsolete. I’m the victim of that disastrous mindset so many times. I need to continuously repeat the “You need to explore” mantra to myself to not be stuck in that comfort trap. Such a heavy task but not impossible.
Those are definitely not all the mistakes that I ever made, but those are the most annoying ones that every programmer can avoid.
If you are interested in OOP and Functional Programming topic, I found an interesting article on Medium about why we should not use OOP, use FP instead — controversial but innovative.
Happy pythoning!