I ask every engineer on my teams to think more. Think about the problem. Think about the solution and the architecture before you open the editor. Think like a pragmatic programmer.
I put it as a ratio: 90% thinking, 10% coding. The numbers are not literal. The point is where the hard work happens. When the thinking is done well, the code is mostly typing.
There is a second reason I push this. Thinking is what makes you able to review. If you have not spent time on different problem statements and how you would solve them, how will you review a design doc from another engineer, or a plan from an AI agent? What will you even ask? How will you counter when the design is wrong?
Coding agents now write more and more of the code. An agent can type faster than any engineer. It still needs someone who understands the problem and can judge whether the solution is right.
When I tell someone to think more
I do not say “think more” at random. It comes up in a few specific situations, and I see them often enough to recognize the pattern.
An estimate without understanding. An engineer gives a timeline before they understand the problem, the existing code, or the edge cases. The estimate is a guess with a number attached.
A one-off when the request is clearly one of many. The engineer builds a narrow, hardcoded fix for the exact case in the ticket. It works. Nobody stopped to ask whether this request was one instance of a bigger concept.
A problem with no proposal. The engineer comes to me stuck, or with a question, and nothing else. No options, no recommendation. I want to help, but I also want them to arrive having already thought about it. “Here is the problem, here are two ways to solve it, I would pick this one because of this tradeoff” is a very different conversation from “this is not working.”
All three have the same root. The engineer moved to action before they had a model of the problem.
Thinking is what makes you a reviewer
This is the part I think most engineers underestimate.
A good design review asks the questions the author missed. Why this data model? What happens when the external API is slow or wrong? What breaks when the second customer asks for something slightly different? Is this the third copy of an idea that already exists in the codebase?
You can only ask those questions if you have thought about similar problems yourself. You build review skill from your own design work. An engineer who always jumps straight to code never builds the library of problems and solutions that good review depends on.
AI agents make this gap matter more. An agent can produce a plan, a design doc, and a working diff in minutes. It will be confident and mostly reasonable. If you hand it an unclear problem, it will hand you unclear code faster. The agent will not tell you that the feature should not exist, that it belongs in a different module, or that it repeats something you already built. You have to see that.
So when I ask engineers to think more, I am also training the skill they will use most with agents. The thinking you do on your own problems becomes the judgment you apply to everything an agent produces.
What I expect before code
Telling someone to think more does not work on its own. It needs a shape. Before an engineer on my teams starts coding, I expect three things.
A written spec or design doc. It does not need to be long. It needs to cover the problem, the approach, the components and contracts it touches, and the edge cases. A reviewer can challenge a spec in minutes. Reconstructing the design from a finished diff takes much longer.
Options with a recommendation. Two or three approaches, compared honestly, with the one you would pick and why. This is the habit I push hardest. It forces you to see the design space before committing, and it gives the reviewer something real to push on.
A walkthrough with me or a lead. The engineer explains the approach out loud and we challenge it. Gaps in reasoning show up fast when you have to defend a choice in conversation. This is also where I learn how the engineer thinks, which tells me what to coach next.
These are cheap compared to rewriting code in review. A wrong decision found in a spec costs minutes. The same decision found in a PR costs a rewrite. Found in production, it costs an incident or a migration.
Think like a pragmatic programmer
The Pragmatic Programmer by Andy Hunt and Dave Thomas is the book I keep returning to for this. Tip 2 in the 20th anniversary edition is “Think! About Your Work.” It is short, and the rest of the book reads to me like an expansion of it.
Four ideas from it shape how I coach.
Care about the craft. Own the quality of the work. Understand why the code works, beyond closing the ticket. The book warns against programming by coincidence, where code works and nobody knows why. That code breaks the moment the coincidence changes.
Right-size the solution. A pragmatic engineer picks a design that fits the size of the problem. A small internal script does not need the architecture of a public API. Building more than the problem needs is a thinking failure too.
State the tradeoff out loud. Every design gives something up. Name what you are giving up, why that is acceptable now, and what would make you change your mind. If you cannot name the tradeoff, you have not finished thinking.
Keep decisions reversible where you can. The book’s Tip 18 is “There Are No Final Decisions.” Plan for change. Treat most decisions as revisable, and know which ones are not.
Where thinking becomes overthinking
The opposite failure is real. Some engineers explore every option, write a long document, and never commit. The design space is only useful if you leave it with a decision.
I use two rules for this.
Timebox it. Give the thinking a fixed window that fits the size of the work, then decide. A timebox turns open-ended exploration into a choice with a deadline. If the window ends and you still cannot decide, that is a signal to bring it to a walkthrough, not to keep thinking alone.
Decide reversible things fast. Spend your thinking on decisions that are expensive to undo: data models, API contracts, integration boundaries, anything other teams or customers will depend on. Move quickly on the rest. A variable name, an internal helper, or the order of two steps can be changed next week. A public contract usually cannot.
Pragmatic thinking means putting the effort where the cost of being wrong is highest.
Same habit, different scope
I ask this of every engineer, fresher or senior. The habit is the same. The scope is different.
For a fresher, thinking means understanding the module or feature in front of them. What does this code do, why does it exist, what happens at the edges, and what is the smallest correct change? They should still write the spec and bring options, sized to the work.
For a senior engineer, thinking means working across systems. How does this change interact with other teams’ modules? Is this request one instance of a pattern? What will the next three requests look like, and does this design block them? Which decisions here are expensive to undo?
This is how I operate, and it is how I have guided many senior engineers.
Think first, then build
When I ask engineers to think more, I am asking them to do the expensive part of the work where it is cheapest. Understand the problem. Lay out the options. Pick one and name the tradeoff. Then build the smallest thing that proves it.
Agents will keep writing more of the code. The thinking you do on your own problems is what lets you judge every design that comes to you, whether a teammate wrote it or an agent did.