Quick answer: Refactor when code's problems—difficulty changing it, recurring bugs, or impeding progress—outweigh the cost and risk of refactoring, not just because code is imperfect. Refactor when the code's problems are actually slowing you down, targeting the parts that most impede progress.

Knowing when to refactor—restructuring code to improve it—means refactoring when the code's problems outweigh the cost and risk of refactoring, not just because code is imperfect. Refactoring when the code's problems are actually slowing you down, targeting the parts that most impede progress, is what makes refactoring worthwhile rather than a distraction.

Refactor when the code's problems outweigh the cost

Refactoring improves code's structure but costs time and carries risk (of introducing bugs), so it should be done when the code's problems outweigh that cost and risk—not just because code is imperfect (all code is imperfect, and refactoring everything imperfect would be endless). The code's problems that justify refactoring are concrete: difficulty changing the code (the code's structure making changes hard and slow), recurring bugs (the code's structure causing repeated bugs), or impeding progress (the code's problems slowing your work). When these problems are significant—the code is genuinely hard to work with, buggy, or slowing you down—the cost and risk of refactoring are justified by the improvement (easier changes, fewer bugs, faster progress), so refactoring is worthwhile. When the code is imperfect but not actually causing significant problems (it works, changes are manageable, it's not slowing you down), refactoring it isn't worthwhile—the cost and risk aren't justified by problems that aren't actually hurting you. Refactoring when the code's problems outweigh the cost—when the code is genuinely hard to work with, buggy, or slowing you down enough to justify the refactoring cost and risk—is the principle for when to refactor, focusing refactoring on the code whose problems actually justify it, rather than refactoring everything imperfect.

Target the parts that most impede progress. Beyond refactoring when problems outweigh cost, targeting the parts that most impede progress focuses refactoring where it most helps. Targeting the parts that most impede progress means refactoring the code that's most hurting you—the parts you most often struggle to change, that cause the most bugs, that most slow your progress—because refactoring these high-impact parts provides the most benefit (the most improvement in ease of changes, reduction in bugs, and progress), while refactoring low-impact parts (imperfect code that isn't really hurting you) provides little benefit for the cost. Focusing refactoring on the high-impact parts—the code that most impedes progress—is what makes refactoring efficient, providing the most benefit for the refactoring cost, rather than spreading refactoring effort across all imperfect code regardless of impact. This connects to prioritizing by impact: refactor the parts whose problems are most impeding you, where the refactoring will most help. Targeting the parts that most impede progress directs the refactoring to where it provides the most benefit, making the refactoring worthwhile. Combining refactoring when the code's problems outweigh the cost (refactoring when problems are significant enough to justify it) with targeting the parts that most impede progress (focusing on the high-impact code) is what makes refactoring worthwhile—refactoring the code whose problems significantly impede progress, where the benefit outweighs the cost, rather than refactoring everything imperfect or low-impact code. Knowing when to refactor this way—when problems outweigh cost, targeting the parts that most impede progress—is what makes refactoring a worthwhile investment that improves the code where it most helps, rather than an endless or misdirected distraction. Refactor when the code's problems are actually slowing you down enough to justify the cost, and target the parts that most impede progress, and refactoring is worthwhile, improving the code where its problems most hurt you, rather than the endless refactoring of all imperfect code or the misdirected refactoring of low-impact parts that wastes effort. Refactor the high-impact problems, not all imperfections, and refactoring pays off by improving the code that most impedes your progress.

The first impression is most of the battle

More players leave in the opening minutes than at any other point, which makes the first few minutes the highest-leverage stretch of the whole game — and also the part the developer can least see clearly, having played it a thousand times. What feels obvious to you is often confusing to someone seeing it fresh, and that gap quietly costs you players before they ever reach the good part.

Get the player into the interesting part fast, let them feel competent quickly, and watch first-time players go through the opening without helping them. Nobody quits a game they're enjoying, so making the early minutes land is most of the battle for retention.

Small and finished beats big and abandoned

A folder of impressive unfinished projects teaches far less than a single small finished one, because finishing is where the hardest and most valuable lessons live — the unglamorous final stretch of bug-fixing, polishing, and shipping that ambitious abandoned projects never reach. Each completed game, however modest, builds the finishing muscle and the confidence that make the next one achievable.

So resist the pull of the dream project until you've shipped a few small ones. Scope to what you can actually complete, finish it, and let the experience of shipping make your bigger ambitions realistic.

Trust behaviour over opinions

People are unreliable narrators of their own experience — they're polite, they rationalise, they suggest fixes that miss the real problem. What they do tells the truth that what they say obscures: where they hesitate, where they get stuck, what they ignore, where they quit. The most valuable feedback is usually the behaviour you observe, not the opinion you're offered.

This is why watching beats asking, and why real data about what players actually do beats any amount of speculation. When several people stumble at the same spot, that's a problem worth fixing, regardless of whether any of them mentioned it.

Ship it, then learn from it

No amount of internal deliberation substitutes for the information you get the moment real players touch your game. The assumptions that felt certain turn out wrong, the feature you doubted becomes the favourite, and the problem you never imagined is the one everyone hits. That feedback only exists on the other side of shipping.

So bias toward getting something real in front of real people sooner rather than later. A rough thing that's out in the world teaches you more in a week than another month of private refinement, and every release makes the next decision better informed.

Cut the feature, keep the focus

The instinct to add is far stronger than the instinct to remove, which is exactly why most games drift toward bloat rather than clarity. Every system you add has to be built, balanced, debugged, and maintained, and it competes for the player's attention with everything else. A focused game that does a few things excellently almost always beats a sprawling one that does many things adequately.

When you're tempted by one more feature, ask what it costs and what it competes with, not just what it adds. The discipline to keep a game focused is what lets the parts that matter shine, and it's usually the difference between a memorable game and a forgettable one.

Refactor when the code's problems—difficulty changing it, recurring bugs, or impeding progress—outweigh the cost and risk, not just because code is imperfect. Target the parts that most impede progress, so refactoring is a worthwhile investment in the code that most slows you down, not an endless distraction.