After 20+ years in full-stack web development and DevOps, I’ve learned that one of the most valuable things I can do as a leader isn’t solving problems for my team—it’s teaching them how to solve problems themselves.
The Challenge of Stepping Back
When a developer on your team encounters an issue with their Docker container or can’t figure out why their React component won’t render correctly, it’s tempting to jump in and fix it. After all, you’ve seen this problem dozens of times before and could resolve it in minutes.
But should you?
Whenever we solve a problem for our team members, we deny them the opportunity to develop problem-solving muscles they’ll need throughout their careers. At the same time, completely abandoning them to “figure it out” isn’t leadership—it’s neglect.
I still remember watching a junior developer struggle with a Redux state management issue for hours. My fingers itched to take over the keyboard, but I pulled up a chair and asked questions instead. Two hours later, he had not only fixed the problem but gained a deeper understanding of how Redux works than if I’d told him what to do. The pride on his face was worth every minute of that two-hour investment.
Finding the Middle Path
Here’s how I’ve learned to strike that balance:
1. Ask Questions, Don’t Give Answers
When a developer comes to me with a problem, my first response is almost always another question:
- “What approaches have you tried so far?”
- “Where specifically are you getting stuck?”
- “What does the error message tell you?”
- “What documentation have you consulted?”
These questions validate their struggle while pushing them to articulate the problem more clearly. Often, explaining the issue leads to their own breakthrough.
For example, I once had a developer struggling with AWS Lambda cold, which affected application performance. Instead of telling her to implement provisioned concurrency, I asked, “What happens when a Lambda function hasn’t been invoked recently? What resources does AWS allocate when a new request comes in?” Following this question thread, she implemented provisioned concurrency and developed a more sophisticated warming strategy than I suggested.
2. Point to Principles, Not Solutions
Rather than saying, “Add this line of code,” I try to say, “Remember how JWT authentication works? The token needs to be verified before accessing protected routes.” This reminds them of the underlying principles they already know, connecting their existing knowledge to the current problem.
One of my team lead members was dealing with a complex microservices communication issue. Instead of diving into the code, I drew a simple request/response cycle diagram. I asked, “Which communication patterns does this remind you of?” This prompted him to recognize it as an asynchronous communication problem where he was trying to use synchronous patterns. He then implemented a message queue solution that elegantly solved the issue.
3. Share Stories, Not Instructions
Instead of directly solving their CI/CD pipeline issues, this reminds me of when we migrated to Kubernetes in 2019. We had similar symptoms when our resource limits were misconfigured. Have you checked your pod specifications?” Stories help them see patterns without robbing them of the satisfaction of connecting the dots themselves.
During a particularly challenging database performance issue, I shared how we had solved a similar problem at my previous company by implementing proper indexing strategies. Rather than specifying which indexes to create, the story gave enough context for the developer to investigate her database schema and identify optimization opportunities I hadn’t even considered.
4. Celebrate Problem-Solving Processes, Not Just Results
When reviewing pull requests or during stand-ups, I make it a point to praise not just working code but good troubleshooting: “I noticed you figured out that caching issue by systematically eliminating variables—that’s exactly the right approach.”
During our retrospectives, we have a dedicated section called “Detective Work,” where team members share what they built and how they overcame obstacles. Recently, a developer walked us through how she diagnosed a race condition in our payment processing system. The methodology was so impressive that we’ve incorporated her debugging approach into our team’s playbook.
5. Create Learning Artifacts Together
When we solve a particularly challenging problem, I ask the developer to document both the solution and the process they used to achieve it. This reinforces their learning while creating a resource for the entire team.
We maintain a “War Stories” section in our internal knowledge base where developers document thorny issues they’ve overcome. Each entry includes the symptoms, failed approaches, successful solutions, and key learnings. This has become our most valuable resource for onboarding new team members, saving countless hours of repeated troubleshooting.
When to Make Exceptions (With Time Guidelines)
There are times when direct intervention makes sense:
- When the team is facing a critical production issue with customer impact (immediate intervention may be necessary)
- When a developer has spent excessive time stuck on something foundational (I use a “rule of thumbs” approach here):
- Junior developers: If they’ve been genuinely stuck for more than 2-3 hours on the same problem
- Mid-level developers: After about half a day (4 hours) of focused troubleshooting
- Senior developers: After a full day of work without progress on a single issue
- When the problem is outside their current skill level and represents too big a leap (in these cases, pair programming works better than complete handover)
Even in these cases, I try to solve problems with them, narrating my thought process rather than for them. “Notice how I’m checking the logs first, then verifying the configuration, before making any assumptions about where the bug might be.”
Learning From Your Team: Reversing the Mentorship Flow
One of the most valuable lessons I’ve learned as a seasoned developer is that expertise can become a limitation. After 20+ years, I have established patterns and approaches that work—but they might not always be the best or most current solutions.
Our newer team members, especially those fresh from computer science programs or coding boot camps, often bring cutting-edge approaches I wouldn’t have considered. Here’s how I stay open to learning from them:
1. Ask for Alternative Approaches
When I suggest a solution, I make it a habit to ask, “Is there another way you might approach this?” Recently, a developer who had just joined us from a fintech startup showed me how to use React Hooks to replace nearly 300 lines of class component code with just 50 lines of functional component code. I had been resistant to hooks, but seeing this elegant implementation changed my perspective.
2. Create Technology Radar Sessions
Monthly, we have an informal session where team members can present new technologies, libraries, or approaches they think might benefit our stack. A recent graduate introduced us to Deno, leading us to adopt parts of its security model in our Node.js applications. Had I dismissed this as just “another JavaScript runtime,” we would have missed out on valuable security improvements.
3. Practice “Reverse Shadowing”
Occasionally, I ask to “shadow” a junior or mid-level developer as they work through a problem or build a feature. I explicitly state that I’m there to observe and learn, not to guide. During one such session, I watched a developer use a GitLab CI/CD feature I didn’t know existed, which has since transformed our deployment process.
4. Admit What You Don’t Know
The phrase “I’ve never seen that approach before—can you walk me through it?” has become one of my most powerful tools. It signals respect, creates teaching opportunities for the team, and keeps me learning. When one of our interns explained how she was using GraphQL to solve a data overfetching problem that had plagued us for months, my willingness to admit ignorance led to a solution that improved our API performance by 40%.
The Results of Empowerment
The payoff of this approach has been tremendous:
- Team members develop a deeper technical understanding
- Problem-solving skills improve across the entire organization
- Fewer bottlenecks when I’m unavailable
- Greater job satisfaction as developers experience the thrill of solving challenging problems
- More innovative solutions than if I’d imposed my own approach
One of our junior developers who joined, barely able to debug a simple React component, is now leading our front-end architecture decisions. The confidence and skills she developed through guided problem-solving—not hand-holding—transformed her into one of our most valuable team members in 18 months.
Building a Problem-Solving Culture
Over time, this approach spreads throughout the team. I’ve watched with pride as mid-level developers began guiding juniors similarly—asking probing questions rather than giving answers, sharing stories rather than solutions.
Our organization has formalized this through a “solve, then share” policy. When you solve a significant problem, you’re expected to share your approach with the team—not just what you did, but how you thought through it. This has cultivated a culture where problem-solving methodology is valued as highly as technical knowledge.
We also celebrate “beautiful detours” when someone takes a non-obvious path to a solution that teaches us something new. One developer’s “mistake” of implementing server-side rendering for a performance issue (when we typically use client-side rendering) revealed performance benefits we hadn’t considered, leading to us adopting SSR for several critical user flows.
This is how you build a team that doesn’t just write code but continues to learn and grow regardless of which technologies come and go. In our industry, that’s the only sustainable competitive advantage.
What strategies have you found effective for empowering your team while still providing guidance? I’d love to hear your thoughts in the comments.
Leave a Reply