Making Room for Junior Developers to Struggle
If struggle is where developers grow, team leads need to protect some of it from AI.
If AI can answer the question, write the code, explain the error, and suggest the fix, then junior developers can move faster than ever.
That is useful. It is also dangerous in a quiet way.

A junior developer can now get through a task without ever building the mental model the task was supposed to teach. The ticket closes. The diff looks fine. The demo works. Then two weeks later, something adjacent breaks and nobody on the team can tell whether they understand the system or just successfully transported AI output from one place to another.
If struggle is where growth happens, then engineering leads need to design for some struggle on purpose. Not every struggle. Not pointless confusion. Not leaving someone alone in a maze because “that is how we learned.” But enough friction that the learning actually sticks.
Code review is not an answer delivery system
When a junior asks a question in review, the fastest thing is to answer it. Sometimes that is the right move. If the issue is a small convention, an obscure framework detail, or something they could not reasonably infer, just tell them.
But when the question points at a missing model, slow down.
Instead of:
This needs to use the existing validation path.
Try:
What do you think happens if this endpoint gets called from the admin flow instead of the signup flow?
Instead of:
You forgot to handle the loading state.
Try:
Walk through what the user sees between clicking save and getting a response.
You are not being coy. You are moving the work back to the place where learning happens: forming a hypothesis, checking it against the code, and adjusting.
A useful rule for review: withhold the answer when the path to the answer is more valuable than the answer itself.
Do not turn every review into a riddle. That gets old quickly, and nobody wants to merge a PR through Socratic performance art. But pick the moments where the developer needs to build judgment, not just patch a line.
Assign tasks with learning friction
AI is very good at flattening tasks into implementation steps. That is helpful for delivery work. It is less helpful when the task exists partly to grow someone.
For junior developers, some tasks should require sitting with a problem before producing code.
That might look like:
- asking them to trace an existing flow before changing it
- having them write down two possible approaches and the tradeoffs
- giving them a bug with incomplete symptoms instead of a ready-made diagnosis
- assigning a small feature that touches a real seam in the codebase
- asking for a test plan before implementation
The point is not to make the work artificially hard. The point is to make the important thinking visible.
A good learning task has a narrow blast radius and a real model to build. “Rename this prop everywhere” is safe but shallow. “Add this validation rule in the same shape as the existing rules, and explain where it should live” is better. It requires reading, comparison, judgment, and a little discomfort.
You can still give guardrails. In fact, you should. Define the boundaries, the files that matter, the expected outcome, and when to ask for help. Then resist the urge to collapse the problem too early.
Pairing should not become remote control
Pairing with a junior often turns into the senior solving the problem while the junior watches politely and occasionally types. Everyone means well. The senior wants to help. The junior wants not to look lost. The code moves forward.
Very little learning happens.
A better pairing session makes the junior drive the reasoning, not just the keyboard.
Try questions like:
- What do you think this function is responsible for?
- Where would you expect this value to come from?
- What would prove this assumption wrong?
- If we did not have AI, what would you inspect next?
- What part of the answer are you confident about, and what part feels guessed?
If AI is part of the session, make it an object of study rather than the pilot. Ask the junior to predict what the AI will suggest before prompting it. Ask them to critique the answer. Ask what context the AI missed. Ask what test would catch the answer being wrong.
The goal is not “no AI while pairing.” The goal is that the junior stays mentally in the loop. AI can be a useful third chair. It should not become the person holding the map.
Set different AI rules for learning and delivery
Teams get into trouble when they have one vague rule for AI use: “use it responsibly.” That sounds reasonable, which is how you know it will mean six different things by Friday.
A clearer distinction is learning work versus delivery work.
For learning work, AI use should be delayed and reflective:
- Try the problem first.
- Write down what you think is happening.
- Identify the exact point where you are stuck.
- Ask AI for help only after you have a hypothesis.
- Compare its answer against the code, not against vibes.
For delivery work, AI can be used earlier, as long as review standards stay high:
- Use AI to draft boilerplate or tests.
- Use it to search unfamiliar APIs.
- Use it to generate alternatives.
- Still own the final diff.
- Be ready to explain every meaningful change.
This distinction removes a lot of shame and confusion. You are not banning the tool. You are saying the purpose of the task changes how the tool should be used.
Sometimes the team needs output. Sometimes the person needs growth. Good leads know which mode they are in.
Watch for cargo-culted AI output
The hard part is that AI-assisted code can look clean. It may even pass tests. The signal is not always in the diff. It is often in the conversation around the diff.
Signs someone may be cargo-culting AI output:
- They can explain what changed, but not why it belongs there.
- They use terms from the AI answer without being able to define them.
- They cannot name the failure case the code handles.
- They accept a suggested abstraction but cannot say what duplication it removes.
- They change three adjacent things when only one was needed.
- They are surprised by basic questions about their own PR.
Do not treat this as misconduct by default. Treat it as a diagnostic. The person may be hiding confusion because the team has taught them that looking fast is safer than looking stuck.
In practice, most leads don’t have time for live walkthroughs. A lower-cost version: leave one targeted comment asking them to explain a specific decision. Not “talk me through everything,” but “why did this logic go here rather than in the service?” The response tells you more than the diff does.
Understanding shows up in adaptation. If they can adjust the solution when the context changes, they probably own it. If the explanation collapses the moment you move one step away from the generated answer, they do not yet have it.
The real learning happens before the code
Senior engineers are increasingly pulled into product conversations, scoping sessions, and early analysis. That work is genuinely hard: taking rough requirements from product, finding the gaps, shaping something buildable. Juniors rarely see it, let alone practice it.
That is where the higher-leverage learning opportunity sits, and it costs very little to open up.
When a ticket lands, ask the junior to write a short analysis note before writing any code. It does not have to be a document. A few paragraphs in the ticket or a thread is enough:
- What problem is this actually solving?
- What assumptions am I making?
- What do I still not know?
- What would done look like? (rough acceptance criteria)
- What is the rough shape of the implementation?
- What could go wrong?
Review it async. Leave a comment if the thinking is off. That five-minute investment catches wrong models before they become wrong code, which is much cheaper to fix.
It also teaches something that PR comments almost never teach: how to shape a problem before touching a keyboard. That is the skill that separates mid from senior, and it does not get practiced enough.
Make stuck visible and safe
None of this works if being stuck is socially expensive.
If junior developers believe they are only valued for clean output, they will use AI to look competent. That is a rational response to the incentives. If you want real learning, you have to make the process visible enough to coach and safe enough to admit uncertainty.
That can be simple:
- In standup, ask “what did you learn?” alongside “what did you finish?”
- In PRs, ask for notes on tradeoffs or uncertainty.
- In planning, mark some tasks explicitly as learning tasks.
- In one-on-ones, talk about when AI helped and when it short-circuited the work.
- Praise good debugging notes, not just merged code.
The message should be clear: struggling with the right problem is not failure. It is part of the job.
The lead’s job is to tune the friction. Too much and people drown. Too little and they glide over the surface without learning to swim.
AI makes that tuning more important, not less. It can remove the boring friction, the repetitive friction, the incidental friction. Good. Let it. But protect the friction that builds judgment.
That is the part junior developers will need later, when the answer is not obvious, the generated code is almost right, and someone has to know the difference.