How far should we take refactoring?

In a recent project, I found myself confronting this question head-on for the first time in a while. The urge to make working code "cleaner" versus the voice saying "that's not the priority right now." Both feel right, and both feel wrong.

There's no clear answer, which is what makes it so troubling. But lately, I've started to feel that the very premise of this question is changing.

Playing It Safe Creates New Dangers

When you keep developing without breaking existing functionality, code complexity increases, and ironically, it becomes harder to maintain. I think this happens in many projects.

Adding new branches beside existing code without touching it. Copy-pasting similar code instead of generalizing. Continuously adding "just make it work" conditional branches.

In the short term, it's safe. But as it accumulates, nobody can grasp the whole picture anymore, and eventually you end up with code where "nobody knows what will happen if you touch it." It's completely counterproductive.

This isn't new. It's the same problem that's been discussed under the term "technical debt."

Accumulate Debt Early, But When Do You Pay It Back?

That said, in early development, prioritizing feature releases over code quality is natural in a sense. You don't yet know what the final form will look like.

The question is how to identify the right timing to pay back that debt.

When the product enters a stable phase. When bug fixes start taking unreasonably long. When the team has some breathing room. There are several "turning points."

However, "we'll do it when we have time someday" never comes. At some point, you need to make the decision: "we're doing it now." But that's a luxury only permitted once the product is on track.

For this question, I've thought the realistic standard is "is it sufficient for the current purpose?" But recently, this standard itself has started to waver.

Technical Debt in the AI Era Has a Different Nature

Particularly recently, a phenomenon has emerged where AI-native development inadvertently produces unmanageable code.

There are aspects that differ from traditional debt.

Code without understanding proliferates. Code written line by line by humans is at least understood by the person who wrote it. But when AI generates it, "it worked, so it's fine," and nobody grasps why it was written that way.

Lack of consistency. Styles and design patterns become fragmented within the same project. AI tends to reset context each time.

Overly complex code emerges easily. AI is good at "making things work correctly," but weak at "keeping things simple." Every time you ask about edge cases, conditional branches multiply.

I've started calling this "understanding debt." As the cost of writing decreases, the weight of the cost to read and understand increases.

But Is That Really True?

However, the premise starts to collapse here.

Actually, I haven't been reading and trying to understand code much lately. I have AI read it for me and explain the overview. When I want to know details, I ask about those specifications.

In fact, even for code that's hard for humans to understand, AI unravels the information faster and more reliably.

If that's the case, how heavy is "understanding debt" really? Honestly, I'm not sure anymore.

When "Just Ask AI" Stops Working

Of course, not everything goes smoothly.

You point out a bug to AI, have it identify the problem area and fix it. But no matter how many times you try, it doesn't reach the root cause. Debug code gets scattered randomly, and the problem remains unsolved.

That's when frustration hits.

There's a unique stress to that phenomenon. With human debugging, even if it takes time, there's a sense of "that wasn't it, let's suspect this next." But AI goes in circles around the same spots, or keeps repeating "I tried adding logs for now."

It looks like trial and error, but actually nothing is being learned. And the code just gets dirtier.

Who Is Refactoring "For"?

This brings us back to the original question.

Refactoring is still necessary. But its purpose is changing.

In the past, "human readability" was the premise. Understandable variable names, short functions. It was all "because humans read it."

But now, if AI can interpret code accurately enough, that premise collapses.

Refactoring for AI.

Keep scope small. Accuracy drops when it exceeds what AI can grasp at once.
Make dependencies explicit. When there's too much implicit coupling, AI misjudges the scope of impact.
Reduce state. When there's too much global state or side effects, AI can't track it.
Increase tests. When AI makes changes, you can immediately determine if something broke.

These overlap with the "good design" principles that have been preached for ages, but the reasoning has changed. Not "because humans can read it easily," but "because AI can handle it accurately."

Is the Optimal Solution Different for Humans and AI?

However, a new question emerges here.

Humans understand through "flow." We read top to bottom and absorb it as a story. So when we're sent to another file midway, context gets interrupted.

But for AI, the cost of jumping to a function definition when it's called is nearly zero. Being split up isn't a problem. In fact, when a single chunk is large, it becomes harder to distinguish what's essential from what's peripheral.

The same applies to abstraction. Humans dislike "over-abstraction" because the scope of impact becomes invisible. But AI is good at enumerating reference points.

In other words, the optimal design might be different for humans and AI.

Should We Prioritize Readability for AI Going Forward?

If opportunities for humans to read code are decreasing. If we can just have AI explain it when we need to read it.

Then we should optimize the code itself for "forms AI can handle accurately," and generate human-facing explanations when needed.

This is a clear-cut decision. But it also makes sense.

It might be similar to writing documentation. Rather than maintaining code and documentation separately, it's more rational to treat code as the source of truth and generate documentation as needed. This trend already exists.

But I Don't Know the Right Answer

To be honest, I don't have an established answer.

Nobody yet knows the "correct answer" for code that's easy for AI to handle. Even if we proceed with splitting and abstraction based on current intuition, it might not actually be best.

Also, the optimal solution might change when the AI generation changes. Code optimized for current models might actually be harder to handle for the next model.

But if we do nothing because we don't know the right answer, we'll never make progress.

Keep things in a form that's easy for current AI to handle, and if it changes, have AI fix it again. The cost of change should be lower than human maintenance. You could think of it that way.

Remaining Questions

Will the refactoring standard become "granularity where AI doesn't get lost during debugging"?
Is human readability really secondary now?
Is the definition of "good code" about to be rewritten?

I still don't see the answers myself.

But one thing I can say is that we've reached a time to reconsider "who is readability for?" And that answer can only emerge from trial and error in the field.

Who are you writing code for?

Recommended Reading

For those who want to learn concrete refactoring techniques, I recommend this book. It introduces a practical approach to gradually improving code using a clear standard called the "5-line rule."

[📦 商品リンク: moshimo-book-5line-refactoring]