Songtham Tung

Is Technical Debt Actually Bad Debt?

Release early, release often — just don’t forget to refactor ;)

Deliver Now

As software engineers, our main objective is to deliver. Once our code works as expected, we commit it and then run it in the CI/CD pipeline.
While seemingly straightforward, it’s not as simple as it may seem. There exists a constant tension in the programming world that stems from shipping fast or slow at the cost of software maintainability aka technical debt.
Technical debt is opting for the easy solution now instead of using a better approach that would take longer. More often than not, many agile teams choose the former than the later.
Deliver now and fix it later is a very popular approach because teams are able to reduce the time it takes to get product-to-market. It’s also great because software engineers don’t have to spend too much time developing something that might be used. For many companies, it’s a fair trade off. Nevertheless, in order to make this approach work, continuous refactoring must be done — else technical debt will accumulate.
The bigger the technical debt, the harder it is to add features.

Fix it Later

“Fixing it later” is synonymous with code refactoring.
Code refactoring is the process of clarifying and simplifying the design of existing code, without changing its behavior.
From the business and end user perspective, this doesn’t affect them since the product doesn’t change. However, from the developers’ perspective, refactoring reduces technical debt and increases software stability.
This makes a huge difference in larger projects.

Code is Read More Often than it is Written

There are a variety of scenarios when one should refactor.
The following is a general list of things to look for when identifying code that could use some refactoring:
Copy & paste (duplicate) codeAmbiguous variable namesUnused variables / methods / classesSuboptimal performanceYour method’s code is longer than your screenViolation of DRY, KISS, YAGNI, SOLID and other software engineering principles
Feel free to suggest any other scenarios in the comments.

Example of Refactoring

In this section, I will show a simple example of javascript code pre and post refactoring.
Pre-Refactoring
// searches MongoDb for all users with a rank limit 10000
User.aggregate([
  {
    $project: {
      _id: "$_id",
      rank: "$rank"
    }
  },
  {
    $match: {
      rank: { $ne: null }
    }
  },
  { $limit: 10000 }
]).then(items => {
  items.forEach(function(i) {
    // Loops through each user to unset the rank
    User.findOneAndUpdate(
      { _id: i._id },
      { $unset: { rank: 1 } },
      { new: true }
    );
  });
});
Post-Refactoring
// unset all users' rank from db
await User.bulkWrite([{updateMany : { 
  filter: { rank: {$exists: true}},
  update: { $unset: { rank: 1 } }
  }
}])
Code Review
  • Results: both example produces the same outcome, which is to unset the users rank.
  • Visually: Pre-refactoring has a lot more code than post-refactoring.
  • Performance: Pre-refactoring makes up to 10000 roundtrips to the database, while post-refactoring makes 1 roundtrip to the database.
Imagine if more developers joined this project and stumbled upon this code. Do you think it would be easier for them to understand and contribute to pre or post refactoring?

Conclusion

Just as the author would improve their writing to make it easier for the readers to understand, developers should also improve their code to make it easier for other developers to understand.
My advice to those in a team where you’re constantly cranking out new features, consider setting aside a sprint or two for stability. Write some unit tests to increase your code coverage and refactor some code to make your apps more robust. I know it might seem like it’ll slow down development time, but it’ll actually increase your team’s efficiency and output in the long run.
Thanks for reading! Originally posted on Santora Nakama.

Tags

More by Songtham Tung

Topics of interest