The Model's Version Was Better and Taught Me Less
I turned autocomplete off for an evening, wrote a small config parser by hand, then compared it with the model's version, and the ordering mattered more than the tool.
Research
The title names the problem: learning to program when an answer arrives before the question.
I have a stake in this. I learned to write code when the only feedback was a compiler and a stack trace. Autocomplete lives in my editor now and I leave it on, because most of what I write at work is not interesting and does not need to be learned.
That is the honest version of my position, and it is why I wanted to test it instead of arguing about it.
What I could not do is run a study. There is no cohort here, no control group, no timing, no test scores at the end. I am not going to dress that up.
What I had was an evening, an editor I control, and a suspicion worth the time: the assistant removes the exact moment where learning happens, the part where the program does not work and I have to guess why.
So I set the smallest test that could still say something. A task slightly past my comfort: a small parser for a config format I use in my homelab, written by hand, with the assistant off. Then, only after it ran, I asked the model for its own version of the same task and compared them by hand.
That comparison is the part worth reading. It separates what the assistant does that usually arrives bundled: it produces answers I have not earned, and it produces vocabulary I could not have guessed. The distance between those is the whole argument.
Setup
Here is the evening, written out so it can be repeated.
Turn the assistant off in the editor settings, so no shortcut brings it back. A completion panel a keystroke away is a panel that is on.
Pick a task just past comfortable. Finishable in an evening, unfamiliar enough that the standard library is not muscle memory. A config parser, a small HTTP handler, a text formatter with an awkward rule buried in it. Anything where the shape of the data is the hard part.
Write all of it by hand, including the boring parts: argument parsing, the error path, the names. Read every message the compiler or interpreter hands back. Keep a scratch file listing each error and what it turned out to mean. That file is the receipt.
When it runs, ask the model for its version of the same task in the same language, with the same constraints on dependencies. Compare by hand rather than by diff tool. A diff shows what changed; reading shows which lines I understood and the model did not, and the reverse.
Then stop for the night. Handing the file back to the assistant to tidy up ends the experiment in the usual place: working code, unchanged understanding.
Findings
What worked was the friction.
The errors I hit by hand are still in my head, with the fixes attached. In my usual loop, where I describe the task, paste the suggestion, run it and accept, the only signal is pass or fail, and by the next morning the file is the only thing that survived.
Then the comparison.
The model’s version was better than mine on every axis a reviewer would use. Shorter, cleaner, and it called a library function I did not know existed to handle a case I had missed. I want to be clear that this is genuine value. The interesting question is when it arrived.
Because I had already written a clumsy version, the model’s code read as an answer to a question I was holding. I could see why the library call was right, because I had spent a long time doing it the long way.
Had I asked before writing, the same code would have been text to skim and paste. Same output, different object.
Ordering is the mechanism. Model-after attaches a name to something I already own. Model-before hands me an answer to a question I never formed, and the answer does not stick, because there is nothing for it to stick to.
Then what broke.
My patience. Somewhere in the middle of the evening I wanted the panel back, badly. That urge pointed at the thing I was avoiding. Syntax was not it.
It was holding the shape of the data in my head at once, deciding what the parser state actually is. That is the work the assistant had been doing for me quietly, and I had not noticed it leaving.
My code quality. By any standard a reviewer would apply, the hand-written version was worse. Longer, clumsier, with a branch that did not need to exist and names I changed a few times. I would have sent it back in a merge request. The artifact was not the point.
Naming. Sitting on a name is uncomfortable, and it forces a decision about what the thing is. A suggestion ends the discomfort early and takes the decision with it. The name gets accepted instead of understood.
Where the assistant genuinely wins: unfamiliar territory. A language I do not intend to keep, a build file, an error message from a toolchain I have never touched, a library with an API I cannot guess.
Hand-writing that is a tax with no lesson attached. The skill is telling it apart from the part I will be debugging at midnight.
The line I drew: skip what I will not debug; grind what I will. State, data shapes, boundary conditions, error handling, the parts that fail quietly and cost hours when they do.
A final thing the evening made obvious. The assistant is patient in the wrong direction. It answers immediately, which is the opposite of what a confused learner needs. Nothing in the loop says sit with this for a while. That sentence is most of the pedagogy.
Boundaries
This is my report of an evening. It is not evidence about anyone else. No cohort, no timing, no scores, no other person repeating the same task. If the result looks thin, it is thin in exactly the way the method is.
It does not prove that autocomplete harms learning. It shows what I noticed when I removed it for an evening, with my own habits in the room. Someone with better discipline could take both the speed and the understanding. That person did not appear here.
It covers writing code, not reading or debugging it. Reading code I did not write is a skill of its own and most of the job. The model may be a good teacher there; I did not check.
It stops holding the moment a deadline is in the room. This protocol is for learning. Shipping is a different job with different rules and no room for the friction I just recommended.
It also stops holding when the task sits below my level. Hand-writing boilerplate I already know teaches nothing, and the assistant is faster at it.
Verdict
Build the habit, keep the tool.
If shipping is the job this week, leave the assistant on and skip the guilt. The moralizing around this topic is mostly noise, and most of it comes from people who paid their dues years ago and forgot the bill. The interesting group is people learning: beginners, career switchers, anyone picking up a language they intend to keep.
For them, the assistant is a tool for the artifact and a hazard for the understanding. I keep mine on for code I already own and off for code I am trying to own.
By the end of my evening the parser ran, it was uglier than the model’s version, and I could sketch the data flow on a napkin without checking a thing. I trust that sketch more than I trust the file.
Pick the smallest task you cannot quite do, close the completion panel, and write it by hand.