All Software Engineering Is Knowing When To Stop
Toni Morrison once said: “All art is knowing when to stop.”
Morrison was a Nobel Prize-winning novelist. But before that, she spent 18 years as an editor at Random House. She wrote her books before dawn. During the day, she cut other people’s work. She was a great writer because she knew what to remove. The first draft is never the finished product. What you cut matters more than what you keep.
I’ve been thinking about this lately. Not about writing. About software.
We Had Slowness, Not Discipline
For decades, writing code was slow. It took real effort to turn an idea into working software. That effort forced you to think. Before every feature, every abstraction, every “nice to have,” you had to ask yourself: is this worth building?
We thought that was discipline. We had process. We had code reviews. We had standards. But looking back, a lot of what we called discipline was just slowness. The effort of writing code did the thinking for us. We just didn’t notice.
Then AI made code generation fast. Really fast. And the slowness disappeared. What came after wasn’t a tooling problem. It was a gap in discipline that was always there. We just couldn’t see it before because everything took so long to build.
AI didn’t break engineering. It showed us how little engineering some teams were actually doing.
Code Is The Aftermath Of Thinking
There is an order to building software. Requirements first. Design second. Code last. Code is the output. It comes after the thinking, not before.
When code was hard to write, you couldn’t skip the thinking. If the ticket said “add a filter,” you built a filter. You didn’t build a filtering framework. The cost of over-building was days of work, so you kept the scope tight. You asked: what do we actually need? You wrote it down. Then you built exactly that. Well, some of us did. I’ve seen people over-building before AI too.
AI changed this. Code is now so cheap to generate that it’s easier to just build something than to think about whether you should. Why write a spec when you can prompt the AI and get working code in five minutes? Why keep the scope tight when the AI will build you a whole framework for free?
So teams skip the thinking. They go straight to generating code. They prompt, they tweak, they ship. What arrives in the pull request is technically correct, well-structure and solves a problem nobody properly defined.
“Let’s see what comes back” is not engineering. It’s vibe coding with better syntax.
The Problem With Plausible Code
Here’s the thing that worries me most: AI doesn’t write bad code.
If it did, we’d catch it. Bad code breaks tests. Bad code fails in review. Bad code is easy to spot.
AI writes code that looks right. Clean syntax. Good patterns. Error handling included. Sometimes it looks better than what a senior engineer would write. In isolation, it’s impressive.
But “looks right” is not the same as “needs to exist.”
I see this a lot. A ticket comes in for a simple change. What comes back is the change, plus an abstraction layer, plus configuration options for future use cases nobody discussed, plus caching because “we might need it later.” The engineer isn’t being lazy. They’re being thorough or that’s what it feels like when the AI generates all of it in two minutes.
But someone has to maintain that code. Someone has to understand it six months later when it breaks. And the cost of maintaining unnecessary code is the same whether a human spent a week writing it or an AI generated it in a minute.
The cost of generating code dropped to zero. The cost of owning it didn’t.
Code that looks right passes review without questions. That’s what makes it dangerous.
Morrison’s Approach
Morrison taught writing at Princeton for almost 20 years. She was tough. But not in the way you’d expect. She didn’t ask her students to write more. She asked them to explain why what they wrote should exist.
Every sentence had to earn its place. If it didn’t serve the story, she cut it. It didn’t matter how good it was. If it wasn’t needed, it was gone.
I think about this when I review pull requests.
Software needs the same approach. The question isn’t just “does this code work?” That’s the easy question. The real question is: “does this code need to exist?”
The role of the senior engineer is changing. A few years ago, the best engineer was the one who could build the most complex system. Today, the best engineer is the one who looks at a pull request and says: “This works. But half of it shouldn’t be here.”
Less about writing code. More about stopping code.
The Fix Is Upstream
AI is not the problem. The problem is that teams stopped thinking before they started building.
Teams that already had good specs, clear requirements, and a clear definition of “done” before AI arrived? They’re fine. AI just makes them faster at what they were already good at.
Teams that depended on the slowness of coding as their safety net? They’re in trouble. The safety net is gone and nothing replaced it.
The answer is not to slow down AI. That’s not going to happen. The answer is to bring back the thinking that should happen before anyone opens an IDE.
Specs first. Requirements first. A clear answer to “what are we building and what are we NOT building” before any code is written.
Code without a spec is just typing.
This is not a new idea. Every methodology ever invented says “define requirements before you build.” We just never took it seriously because the slowness of coding covered for us. That cover is gone now. Without the discipline of thinking first, AI will fill the gap with clean, well-structured, completely unnecessary code.
Knowing When To Stop
The best engineers I’ve worked with at AWS, in gaming, across every team I’ve led share one thing. They write less code than you’d expect. They solve the problem and they stop. No extra frameworks. No “while I’m here” additions. No building for problems that don’t exist yet.
They have what Morrison had. They know when to stop.
AI gave us the power to generate code at the speed of thought. But it didn’t give us the judgement to know when we’ve generated enough. That judgement is human. It’s what separates an engineer from a code generator.
Your team needs to develop it. Your reviews need to enforce it. Your culture needs to value the person who removes code as much as the person who writes it.
All software engineering is knowing when to stop.
Most teams just never had to practice it before.

