LogoTRUONG PHAM
Home
Projects
Blogs
YouTube
Contact

Newsletter

Stay updated with technical artifacts and engineering insights.

LogoTRUONG PHAM

Building scalable software and sharing insights on technology & life.

Sitemap

  • Home
  • Projects
  • Blogs
  • YouTube
  • Contact

Connect

  • GitHub
  • LinkedIn
  • Email
  • YouTube

© 2024 TRUONG PHAM. © All rights reserved.

Privacy PolicyTerms of Service
Back
Blog #39: The 'Will Fix Later' Promise and the Compound Interest of Technical Debt
50 FRONTEND LESSONS – HARD-EARNED EXPERIENCES

Blog #39: The 'Will Fix Later' Promise and the Compound Interest of Technical Debt

The story of 'temporary' code written under deadline pressure and how it returned to attack the system at the most critical moment.

TP
Truong PhamSoftware Engineer
PublishedJuly 25, 2024

1. The Context

The biggest sales campaign of the year (Black Friday) was only 3 days away. The checkout page interface suddenly glitched: "Unable to calculate taxes for customers in certain geographic regions." I opened the price calculation logic file, and immediately hitting me was a comment I had written myself... 2 years ago:

// TODO: @ivan - Refactor this hardcoded logic after integrating the new tax API. Rushing for launch.

At that moment, I froze. My heart skipped a beat. That "Will fix later" from 2 years ago was now a "fuse" threatening the operation of the entire business on its most important day. I felt guilty and profoundly regretful. The pressure now wasn't just to fix the bug, but to face my own past procrastination.

2. Foundational Knowledge

Technical Debt is a familiar concept. It's like borrowing money. You choose the fast way (borrowing money) to achieve a short-term goal (buying something immediately). But all money comes with interest. The "interest" on technical debt is the difficulty in maintenance, slower development speed, and increased risk of system collapse.

The problem isn't that you're not allowed to "borrow." The problem is you must manage it. If you keep borrowing without a plan to pay it back, eventually, the "interest" will consume all your effort.

3. The Specific Problem

Two years ago, when integrating the tax system, the partner's API wasn't ready. To make the launch day, I wrote a "temporary" function by hardcoding geographic region codes into the Frontend.

// The "temporary" source code that survived for 2 years
const calculateTax = (regionCode, amount) => {
  if (regionCode === 'SG' || regionCode === 'HN') {
    return amount * 0.1; // 10% VAT
  }
  // TODO: @ivan - temporary placeholder, call Tax Service API later
  return 0; 
};

The system then only had a few hundred users. But 2 years later, the company had expanded to 64 provinces and international markets. That "temporary" function had silently caused financial loss for the company for a long time by miscalculating taxes in other regions.

4. How I Handled It

I had to drop everything else to focus on "paying the debt." My initial solution was to continue "patching"—adding dozens of if/else checks to the old function for Black Friday. But I realized if I did that, I would be borrowing yet another loan at an even higher interest rate.

I decided to use the next 24 hours to do the right thing:

  1. Call the API directly from the Backend for tax calculation.
  2. Write an independent currency and tax utility suite with 100% Unit Test coverage for region codes.

I used Jest to simulate every Backend API failure case to ensure the Frontend never unilaterally decided tax rates again.

5. Trade-offs

Doing the "right" thing in a rush has a fatal drawback: Risk. Changing core logic right before a big day is extremely dangerous. We could have broken the entire checkout process if the new API had issues.

Comparison:

  • The quick fix: Add 10 if/else checks. Takes 30 minutes. Low immediate risk, but high technical debt.
  • The sustainable fix: Integrate the new API. Takes 1 day. High immediate risk (due to the deadline), but completely eliminates the technical debt.

I chose the sustainable way and accepted staying at the office until 4 AM to monitor every possible risk.

6. Lesson Learned

I learned a lesson I'll never forget: There is no such thing as 'Temporary' in programming. Whatever is running will stay forever until it breaks.

  • Advice: Never write a TODO without a corresponding ticket in the backlog or a specific deadline to delete it.
  • Self-reflection: Was I over-engineering by trying to write polished tests in the heat of the moment? I doubted myself too. But after discovering that the new code caught 3 potential logical errors thanks to Unit Tests, I knew I had done the right thing.

Juniors are often excited because "a quick fix is done." But a true Senior is someone who worries about code that is "done and forgotten." If you must choose a fast way for a deadline, make sure you pay that debt back in the very next Sprint.


Notes on the price of procrastination in source code.

Series • Part 39 of 50

50 FRONTEND LESSONS – HARD-EARNED EXPERIENCES

NextBlog #40: Don't try to be smart – Write code for humans, not for machines
Blog #38: Micro-frontend Reality Check – When theoretical glory meets harsh reality
34Blog #34: My Machine Runs Smooth, the User's Machine Smokes35Blog #35: Clean Architecture – The Dream and the Harsh Reality36Blog #36: Touching Legacy Code – When a refactor effort becomes a disaster37Blog #37: The Reusability Trap – When a 'multi-purpose' Component becomes a burden38Blog #38: Micro-frontend Reality Check – When theoretical glory meets harsh reality39Blog #39: The 'Will Fix Later' Promise and the Compound Interest of Technical DebtReading40Blog #40: Don't try to be smart – Write code for humans, not for machines41Blog #41: The 2 AM Panic and Infinite Question Marks42Blog #42: When the Backend Changes the Schema and the Fragility of the Frontend43Blog #43: CORS Isn't Always the Backend's Fault44Blog #44: CI/CD and Environment Variables that 'Disappear' Without a Trace
TP

Written by Truong Pham

Software Engineer passionate about building high-performance systems and meaningful experiences.

Read more articles