Emmanuel EbriEmmanuel Ebri
Back to Blog
Code ReviewAI-Assisted DevEngineering Practice

Reviewing Code You Did Not Write

The skill the industry now runs on, and nobody teaches it

6 min read

Reviewing Code You Did Not Write cover

There is a question I now ask myself before every commit, and it has nothing to do with whether the code works.

Can I explain this to someone who is annoyed with me?

Not narrate it. Explain it. Say why this line exists, what happens if it is removed, what I considered instead. That question has become the hard part of my job, because a large share of the code I ship in a given week was drafted in seconds by a model, and reading it takes far longer than generating it did.

The industry noticed the generation part. Everyone has an opinion about how much faster teams are now. Almost nobody is talking about the other side of that trade, which is that the bottleneck moved. It used to be typing. Now it is comprehension, and comprehension does not scale the way generation does.

What used to make review work

Code review as a practice was built on an assumption that is quietly disappearing. The assumption was that somebody understood the code.

When a colleague opened a pull request, they had spent hours in the problem. They had tried the approach that did not work. They knew which line was load bearing and which was leftover. My job as a reviewer was to bring a second perspective to a decision that had already been reasoned through once. I was checking the reasoning, not reconstructing it.

That is no longer the default. When the author of a diff is a model, nobody has done the reasoning yet. The pull request arrives complete, formatted, plausibly named, and unexamined. If I review it the old way, looking for style issues and obvious mistakes, I am checking the packaging of something whose contents nobody has opened.

The uncomfortable version of this: a diff that looks clean is now weak evidence that anyone thought about it.

Where the review has to start now

I stopped treating review as a final pass and started treating it as the first time anyone actually engages with the logic. That changes what I look for.

The first thing I do is read the whole thing with the editor closed and try to say out loud what it does. Not what each line does, what the unit accomplishes. If I stall, that is the finding. I do not keep reading in the hope that context arrives later, because it will not. I go back and ask specific questions about the part that stalled me until I can restate it without looking.

Then I run three questions against every branch that touches state.

What happens if this runs twice. What happens if it fails halfway. What happens if two of these run at the same time.

Those three cover most of what I have actually shipped as bugs. They are also exactly the questions that a plausible looking implementation tends to fail, because they are about the environment the code runs in rather than about the code itself.

The protocol, written down. Step three is the one people skip.

The step people skip is the fourth one. Break it on purpose. Remove the guard, delete the await, drop the lock, and see whether anything complains. If nothing does, I have learned something valuable. Either the guard was decoration, or the test that should have caught its removal does not exist. Both are worth knowing before a user finds out.

I want to be clear that this is not slower than writing the code myself. It is slower than not reviewing, which is what the alternative usually is in practice.

Ownership is a real thing, not a feeling

There is a version of this argument that turns into a purity test, where anything a model touched is suspect and real engineers type everything themselves. That is not my position and I do not think it survives contact with a deadline.

My position is narrower. Whatever process produced the code, one human has to be able to defend every line of it, and that human is whoever's name is on the commit.

The practical way I get there is to rewrite something. Rename the variables to match the conventions in the rest of the file. Pull an inline block into a named function. Reorder the guards so the cheapest check runs first. None of that changes behaviour, and all of it forces me to hold the whole thing in my head at once, which is the only reliable way I know to convert code I received into code I own.

The commit message is the tell. If I can write a message that explains why the change was needed, in terms of the system rather than in terms of the diff, I understood it. If the best I can do is describe what the lines say, I did not, and I go back.

What this costs, and what it buys

The cost is real time on every change, and it does not compress. There is no version of this where I get faster at understanding by understanding less.

What it buys is the ability to change the system later. Code nobody understands is not an asset, it is a liability with good syntax. It works until the day it needs to change, and then it stops the team, because modifying code you cannot explain is either guesswork or a rewrite.

I have shipped both kinds. The parts of my platform I can explain are the parts I still improve. The parts I cannot are the parts I route around, add flags to, and quietly resent. The generated code did not cause that pattern, it just made it much easier to produce at volume.

The thing I would tell a team adopting this

Make the review protocol explicit and write it down, because the old one is now insufficient and everybody is improvising privately.

Say out loud that the reviewer's job includes reconstructing intent, not just checking it. Budget for that. If a pull request takes twenty minutes to generate and forty to review, that is not a failure of the tooling, that is the actual shape of the work now.

And treat "I cannot explain this yet" as a normal, sayable thing rather than an admission of weakness. The alternative is a codebase where everyone assumes somebody else understood it, which is how you end up with software that nobody can touch and nobody will admit to not understanding.

The code was never the hard part. It just used to look like it was.

I build EdTech and fintech products at E-Bringgs Technologies. This is the review protocol I actually use, refined mostly by the times I skipped it.