Programming with AI
ENRU
3.6

Template — refactoring

changing the shape without touching the behaviour

What it is

Refactoring is changing code without changing what it does. Splitting a long function, lifting out a repeat, renaming things so a human can read them. From the outside, after a refactoring, everything works exactly as before.

Hence the main difficulty of the request: you have to say explicitly that the behaviour must not change. Otherwise the AI takes the task as "make it better" and adjusts the logic along the way — which is not refactoring, and now everything has to be re-checked.

What it looks like in code

The template

Prompt
What's wrong: <why the code needs reworking>
What to do: <which change of shape>
Behaviour stays: <what must work exactly as before>
How I'll check: <what proves nothing broke>

Bad

Don't
Refactor handlers/weather.py, make it nicer

"Nicer" is an invitation to rewrite the file from scratch. You get a different architecture, different names, edge cases fixed (or broken) in passing, and a diff nobody can read.

Good

Better
What's wrong: the cmd_weather function is 80 lines and mixes
the API request, parsing the reply and building the text.

What to do: split it into three functions — fetch, parse, format.
Leave cmd_weather as the entry point; it only calls them in turn.

Behaviour stays: the reply texts, the log format and the error
handling remain exactly the same, down to the character.

How I'll check: I'll run the same three commands as before and
compare the bot's replies word for word.

What to tell the AI

The sentence not to start without

The behaviour stays the same.

Write it outright, even when it seems obvious from the word "refactoring". For an AI that word is vague: in the training data it covers both renaming a variable and rewriting a module from scratch.

Refactoring and a feature are separate passes

The temptation is strong: while we're in this file anyway, let's add a cache. Don't — and here is why. If something breaks afterwards, you won't know whether the refactoring broke it or the new feature did. Kept apart they are diagnosed instantly; mixed together, in hours.

Prompt
For now only split it into functions, with no change in behaviour.
We'll add the cache as a separate next step.

What to check with

Tests are best: run them before, run them after, the result matches. If there are no tests, a manual check will do, but it has to be described in advance — otherwise after the change you find there is nothing to compare against.

A trick that costs a minute: before the refactoring, save the program's output for a few inputs to a file. Afterwards, compare.

python bot.py --dry-run > before.txt
# ... refactoring ...
python bot.py --dry-run > after.txt
diff before.txt after.txt

An empty diff means the refactoring went cleanly.

What to look for

A diff bigger than it should be. Splitting a function into three means moving lines, not rewriting them. If almost every line in the diff is changed, the code was rewritten from scratch and the behaviour has almost certainly drifted.

The texts changed. The most common uninvited improvement: the AI "tidies up" the messages to the user. "City not found" becomes "Unfortunately, the specified city could not be found 😔". A small thing, and already a change of behaviour.

New dependencies or abstractions appeared. A base class, a factory, a decorator — where all you asked for was splitting a function. A sign the AI was solving its own problem rather than yours.

Edge handling disappeared. The empty-list check, if not data, an early return — in a rewrite these lines are the first to be lost, because they look optional.

Cheat sheet

  • Four lines: what's wrong · what to do · behaviour stays · how I'll check.

  • Write "the behaviour stays" explicitly; the word "refactoring" does not guarantee it.

  • Refactoring and a feature are separate passes and separate commits.

  • Save the output before and after, compare with diff.

  • A big diff when splitting a function means the code was rewritten, not moved.