Refactoring and technical debt

Play this lesson

Why is everything slower?

A year after launch, Remy adds the Frost Beetle to Garden Defense. The Night Moth took two days last spring. The Frost Beetle takes a week. Every change breaks something else: the Halloween code has if (halloween) in 14 different files, and nobody remembers what speed2 means.

Nothing is broken for players yet. But the code has become slow and scary to change. That has a name: technical debt.

Borrowing time

The programmer Ward Cunningham came up with the debt idea in 1992. A shortcut is like borrowing time: we ship sooner today. But messy code charges interest, the extra time every later change costs. If a feature takes 4 days in clean code and 6 days in messy code, the 2 extra days are the interest.

Some debt is a fine choice, like a quick hack to get the Halloween event out on time. The mistake is never paying it back. Write it down as a GitHub Issue with a tech-debt label, so it doesn't get forgotten.

Quick check

In the debt picture, what is the "interest"?

  1. The extra time every later change costs because of the messy code
  2. The money the studio pays GitHub each month
  3. The time spent writing the first, quick version
Show the answer

The extra time every later change costs because of the messy code

The shortcut saves time once. The interest is paid again and again, every time someone has to work around the mess.

Code smells

A code smell is a sign that something may be wrong underneath. In a live game, smells pile up with every event, every midnight hotfix, and every AI change nobody read closely.

Spot the smell

pests.js
function spd(p) {  if (p.t === 'snail') return 1.8;  if (p.t === 'beetle') return 1.8 * 1.5;  if (p.t === 'moth') return 1.8 * 1.5;  return 2;}

Kai wants to make beetles a little faster for a balance test. What is the biggest problem with this code?

  1. The speeds are unexplained magic numbers buried in code, so tuning one pest means editing code and guessing what 1.8 and 1.5 mean
  2. The function is too short to be real game code
  3. Using return inside if statements makes the game run slowly
Show the answer

The speeds are unexplained magic numbers buried in code, so tuning one pest means editing code and guessing what 1.8 and 1.5 mean

Nobody can tell what 1.8 or 1.5 stand for, and the short names spd and p.t don't help. Named values in balance.json, like beetleSpeed, would let Kai tune one pest without touching code.

Refactoring: same game, better code

Refactoring means changing the structure of code without changing what it does. Martin Fowler, who wrote the classic book on it, describes it as a series of small steps that each keep the behaviour the same.

Quick check

A refactoring pull request that also adds the new Frost Beetle is fine, because it saves time.

Show the answer

False

A refactor should change no behaviour, so passing tests prove nothing broke. A new pest changes behaviour on purpose, and the reviewer can no longer tell which change is which. Two small pull requests are safer.

Refactoring with Claude

Claude Opus 5.5 is good at refactoring, if we set it up safely:

Prompt pick

Remy wants Claude to clean up the Halloween checks spread across 14 files. Which prompt is safest?

  1. "On a branch, add tests for how Halloween works now, then move its checks into events.js in small commits, running the tests after each. Behaviour must not change."
  2. "Rewrite Garden Defense properly, it's a mess. Push to main when you're done."
  3. "Remove the Halloween code and add the Frost Beetle while you're in there."
Show the answer

"On a branch, add tests for how Halloween works now, then move its checks into events.js in small commits, running the tests after each. Behaviour must not change."

Tests first, small steps, a branch and a clear rule that behaviour stays the same. The second risks the version players use, and the third mixes removing a feature with adding one, so nobody can review it properly.

Budget it, and beware the rewrite

Pay debt back a little at a time. Our studio keeps about one day in five of every update for refactoring, starting with the code that changes most, because that's where the interest is highest.

Starting from scratch is tempting, and usually a trap. In 2000, the programmer Joel Spolsky called Netscape's choice to rewrite its browser from scratch "the single worst strategic mistake that any software company can make". Netscape went almost three years without a major release while rivals moved ahead. Old code holds fixes for real bugs, so replace it piece by piece instead.

Bolt says: Healthy code is easier to fix in a hurry. Next: when things break, with outages, attacks and backups.

Fact-checked 9 October 2026