
When Staying in the Flow State Goes All Wrong
Your no-BS weekly brief on software engineering.
Join 100,000+ developers
Is Friction Ever a Good Thing?
As a child, I was once asked a simple question about friction: If friction keeps things from moving smoothly, is it ever a good thing?
My immediate answer? No! If I'm running, biking, or even just walking, why would I want something to slow me down? I want the full force of my momentum, the power of my legs carrying me forward, uninhibited and unstoppable!
But if you've ever walked on ice, you know exactly how flawed this thinking was. Sometimes, you desperately need friction. Whether you're walking, driving, skiing, or sledding, the ability to slow down, to maintain control, is what keeps you from wiping out.
Flow State: The Ice Under Your Feet
So how does this relate to coding? Why wouldn't you want to get into a flow state and just let your fingers fly?
Well, just like walking on ice, you're bound to have a bad time if you’re always in a flow state.
I know, I know—you’re thinking, "Typecraft, I just saw your video on the flow state! You talked about how it was so great to ignore your manager (I DID NOT SAY THAT) and just sling that code."
And yes, flow state is amazing. When you’ve got a clear mental model and a well-paved road in front of you, flying through code can feel effortless. But sometimes, when you don’t quite know what you’re coding—when the path is uncertain—it’s like driving on ice. You need to slow down, take control, and make sure you’re not skidding into a ditch.
The Ditch
You may have heard me reference "Manage Controller" as a costly mistake I had early in my career. This was a classic example of getting into the Flow State
and running invariably into trouble. You see - I had fallen in love with an ivory tower of a solution. That solution was "one controller to rule them all."
You see — I realized that as an admin of the system I was working on, you would have to manage these various business objects. It was all CRUD after all. With the right approach, I could build one controller to rule them all. It was going to be glorious and it would just all work ™.
I can still remember sitting in the Ace Hotel in the NoMad neighborhood of Manhattan. With its dimly-lit lobby that was perfect as a place to work, my fingers flew. My vision was clear. I knew where I was going as I concocted an architectural approach that would make this API so easy to work with.
I even debated the merits of this approach to others.
My fingers continued to fly.
I remember the moment the cracks started to show. A slight feeling of unease, then a realization that something wasn’t quite right. The elegance I imagined was turning into an unmanageable mess. And by then, it was already too late.
The frustration, the late-night debugging, the painful refactoring—it all could have been avoided if I had just slowed down.
Lessons Learned
- If it feels like an ivory tower solution, it probably is.
- If you introduce abstraction to remove duplicate code, you're inherently coupling code to some degree. Always consider the trade-offs.
- We’re all fallible—embracing this helps us look at solutions (even our own) more objectively.
- Slow down when making sweeping changes. The cost of undoing them can be massive.
Five Times You Should Pump the Brakes
Here are five scenarios where friction in your workflow is actually a good thing.
1. When You're Writing New Architecture
Flow is great for solving well-scoped problems, but when you're making foundational decisions—whether it's designing a database schema, structuring an API, or choosing a framework—you need to engage System 2 thinking. Daniel Kahneman, in Thinking, Fast and Slow, describes System 2 as deliberate and effortful thinking—exactly what's needed for making architectural decisions. Flow (System 1) can push you to act on instinct, but instincts aren’t always right.
Slow Down Strategy: Instead of diving straight into implementation, start with a brief POC (proof of concept) to get a feel for what works and what doesn't. This isn’t meant to be perfect but should help surface potential issues. You can refine from there or discuss with your team before committing to a direction.
2. When You're Debugging a Hard Problem
Debugging in a flow state often means following intuition—making quick changes and re-running code. But some problems are deceptive. That quick "fix" might just be covering up deeper issues.
The Confirmation Bias Trap
When debugging, we tend to look for evidence that supports our existing assumptions. If we think the issue is in the database query, we might only examine logs and SQL execution plans—ignoring the fact that the problem could be in an unrelated caching layer. This kind of tunnel vision, fueled by flow state, makes it easy to miss the real issue.
Example: A developer spends hours optimizing a slow database query, only to realize later that the real issue was a missing index—not inefficient SQL logic. The assumption that "the query itself must be the problem" led them down the wrong path.
Slow Down Strategy: Instead of assuming where the problem lies, take a scientific approach: - Form multiple hypotheses, even unlikely ones. - Actively seek evidence that disproves your assumptions. - Use debugging tools methodically—check logs, trace execution paths, and isolate variables before making changes. - Ask someone else to challenge your thinking. Fresh eyes can break the cycle of confirmation bias.
Taking these steps forces you out of the flow-induced bias trap and ensures you're solving the right problem.
Friction as a Feature
Mastering code isn’t about moving the fastest—it’s about knowing when to move fast and when to slow down. The best developers don’t just embrace flow; they know when to step back, reflect, and refine.
Think of friction as your silent ally. The slight resistance before a big decision, the hesitation before an abstraction, the pause before committing a change—these aren’t obstacles. They’re guardrails that keep you from veering off course.
The best developers aren’t just fast—they’re thoughtful. They recognize that slowing down in the right moments leads to cleaner code, better decisions, and fewer late-night debugging sessions.
So next time you’re deep in flow, ask yourself: Am I driving on solid ground, or am I about to hit an icy patch? Because sometimes, the best way to move forward is to slow down first.