Don’t leave traps in your codebase

Thiago Ferreira
4 min readJan 8, 2023

--

Photo by manu schwendener on Unsplash

If you don’t know me personally, here’s something about me: I’m an awfully clumsy person. If there is a glass in the corner of the table, I’ll eventually knock it off to the floor. It’s not a matter of IF, but WHEN. I’m sure I’ll break stuff eventually if I have the chance to 😂

Ok, how does this relate to coding, then?

In my life, I developed a system to help me with my clumsy nature. I don’t leave glasses in the corner of tables, I don’t leave things in places that I know I’ll break/damage somehow.

I ended up learning the same precautions can be applied in my work/career to avoid breaking stuff — for myself and for others.

Here are a few common traps we leave in our code and how to overcome them

Low test coverage

Low test coverage in software means that not all parts of the code are being tested in an automated manner. This can have several negative consequences:

  1. Bugs and defects may not be detected before affecting the real world
  2. It is difficult to determine the quality and reliability of the software
  3. It is difficult to make changes to the code, as you can’t be sure of what will break without running extensive manual tests.
  4. Extra difficulty in finding the root cause of problems, which may affect the team’s ability to fix issues in a timely manner.

I consider low test coverage a trap in the codebase because similar to my personal issue of knocking glasses out of the table, it’s not a matter of IF this will be a problem. It’s a matter of WHEN.

In conclusion, a low test coverage decreases the quality and reliability of the software and makes maintenance and improvement harder over time.

Missing documentation

A huge part of my day-to-day as a software engineer is conveying information from one place to another. Sometimes is moving information into my brain, or vice versa.

When we are working actively on a project, we have a lot of information fresh and easily accessible in our minds. As time passes, we will certainly forget a good portion of that information.

If we do not make a conscious effort to document information in the correct channels, we are causing problems for your company. Quoting Bob Martin, author of the Clean Coder, one of the first things professionals need to have in mind is “to not cause problems”.

Documenting information properly is part of our job and part of our responsibility as professional software engineers.

Aside from that, here are other problems that missing documentation can cause:

  • It can be difficult for new team members to understand the code and become productive
  • Difficulty to maintain the code: similar to the lack of unit tests mentioned above, no documentation means that whoever is going to make changes in the code will have to figure it out on their own — and this will take time.
  • It can be difficult to use the software: Without proper documentation, how are you supposed to know what the code is supposed to do/ or even capable to do?
  • Different folks will work in this code in the future: as time passes, the author of a project may not be involved anymore. This is actually the most common scenario. Documenting things in time ensure that people won’t take crucial information with them when they leave.

Over-complicated code

You might get away with missing documentation if you write code that is simple, concise, and easy to read.

Well-written code can serve as documentation, so be sure to make your code as simple and as readable as possible.

Here’s an example of an over-complicated code (with high cyclomatic complexity) and how we can fix it:

def calculate_discount(price, customer_type, item_type):
if customer_type == 'regular':
if item_type == 'clothing':
return 0.1 * price
elif item_type == 'furniture':
return 0.2 * price
else:
return 0.15 * price
elif customer_type == 'premium':
if item_type == 'clothing':
return 0.2 * price
elif item_type == 'furniture':
return 0.3 * price
else:
return 0.25 * price
else:
if item_type == 'clothing':
return 0.15 * price
elif item_type == 'furniture':
return 0.25 * price
else:
return 0.2 * price

This can be refactored into the following code, which is a lot simpler to read and understand:

 def calculate_discount(price, customer_type, item_type):
discounts = {
('regular', 'clothing'): 0.1,
('regular', 'furniture'): 0.2,
('regular', 'other'): 0.15,
('premium', 'clothing'): 0.2,
('premium', 'furniture'): 0.3,
('premium', 'other'): 0.25,
('other', 'clothing'): 0.15,
('other', 'furniture'): 0.25,
('other', 'other'): 0.2
}

return discounts[customer_type, item_type] * price

“Traps” == Technical Debt?

Technical debt refers to the accumulation of shortcuts, hacks, and unfinished work that will eventually cause problems for the team, like missing deadlines, poor code quality, more bugs, and taking a longer time to finish projects.

Just like financial debt, technical debt accumulates interest and becomes really expensive over time.

All the “traps” mentioned above can be considered technical debt. It’s normal for teams to deal with technical debt, as sometimes we have to make tradeoffs to finish projects.

It is important though to not lose track of the technical debt and allocate resources to clean it up on a regular basis — which is important for the team’s efficiency in the long run.

Conclusion

I have used this approach for years in my career (and personal life) and “not leaving glasses on the corner of the table”, figuratively or not, has been paying off really well for me and helping me avoid all sorts of problems.

Another way to think about this is by making an intersection with the world of cooking. There is a french expression “Mise en place”, which means putting everything in order/in the correct place to be able to work smoothly. That’s a way to think about coding too: everything should be in the correct place.

Thank you for making it this far in this peculiar thought 🙌🙏 I hope it was helpful!

--

--