Rain Lag

The Two-Phase Coding Session: Separating Thinking and Typing to Ship Cleaner Features Faster

How deliberately separating your work into a planning/thinking phase and an execution/typing phase leads to cleaner code, fewer defects, and faster delivery.

The Two-Phase Coding Session: Separating Thinking and Typing to Ship Cleaner Features Faster

Most developers mix two very different activities into one messy, exhausting session:

  • Thinking: understanding requirements, designing flows, making trade-offs
  • Typing: implementing decisions as code, wiring things up, fixing compilation errors

When you try to do deep design and detailed implementation at the same time, you pay a heavy price:

  • Context switching between “big picture” and “tiny detail”
  • Half-baked designs revised mid-implementation
  • Accidental scope creep
  • More bugs and rewrites

A simple but powerful alternative: run your work as two distinct phases — a deliberate Planning/Thinking Phase and a focused Execution/Typing Phase. By separating these, you can ship features faster, with fewer defects, and with cleaner, more maintainable code.


Phase 1: The Planning/Thinking Mode

In the planning phase, you resist the urge to jump into your IDE. Your goal is to make all the important decisions before your fingers touch the keyboard.

This phase focuses on four main activities:

  1. Clarify user stories and scope
  2. Design the architecture and interfaces
  3. Assess risks early
  4. Define what “done” looks like

1. Write crystal-clear user stories

Good code starts with good understanding. Before you write any implementation code, write user stories that clearly express:

  • Who the feature is for
  • What they’re trying to accomplish
  • Why it matters (user value)
  • How you’ll know it works (acceptance criteria)

A solid user story might look like this:

As a team admin, I want to invite users by email and assign them roles so that I can onboard new teammates securely without involving IT.

Acceptance criteria example:

  • Admin can invite one or more email addresses
  • Each invite must specify a role (viewer, editor, admin)
  • Invites expire after 7 days
  • Existing users with the same email are not re-created
  • Audit log records who invited whom and when

Once these are written, you now have an objective scope and a shared definition of success. This cuts down on “while we’re here, let’s just add…” surprises mid-implementation.

2. Design scalable, maintainable architecture

Next, design how this feature fits into the system. Stay out of the code editor; instead, use:

  • Quick diagrams (whiteboard, notebook, Miro, etc.)
  • Text-based architecture notes
  • Sequence diagrams or API contracts

Aim to answer questions like:

  • Where does this logic live? (service, controller, client, worker?)
  • What data models are involved? (new tables, fields, or objects?)
  • What are the interfaces? (input, output, error cases?)
  • How does this scale? (traffic, data growth, concurrent usage?)
  • How will we test it? (unit tests, integration tests, feature flags?)

In this phase, you want to design something that is:

  • Composable: small units that can be reused
  • Testable: clear boundaries, inversion of control where needed
  • Extensible: you can add features later without ripping everything apart

The goal isn’t a 50-page document; it’s to make the core design decisions explicit so that implementation later becomes a straightforward translation.

3. Run an explicit early risk assessment

Most surprises in software projects are not truly surprising – they’re just not surfaced early enough.

During planning, pause to ask:

  • Technical risks

    • Are we integrating with unfamiliar APIs or legacy systems?
    • Are there performance or scaling concerns we don’t fully understand?
    • Is there tech debt that might slow us down?
  • Product risks

    • Are we sure the requested behavior actually solves the user’s problem?
    • Is the UX clear and consistent with the rest of the product?
    • Could this feature clash with future roadmap items?
  • Timeline risks

    • Are there dependencies on other teams or services?
    • Are there unclear requirements that need stakeholder input?
    • Are we trying something we’ve never done before?

Write these down. Decide what you’ll do about them before coding:

  • Spike small prototypes
  • Clarify with stakeholders
  • Reduce scope where possible
  • Add feature flags or rollout controls

By de-risking early, the implementation phase becomes more predictable and less stressful.

4. Define “done” up front

“Done” is not “it compiles” or “it works on my machine.” Define done in terms of:

  • Functionality: all acceptance criteria met
  • Quality: tests written and passing; basic performance verified
  • Maintainability: code readable, documented where needed
  • Operational readiness: logs, metrics, alerts (if relevant)

This checklist guides your future self during the typing phase and keeps you from declaring victory too early.


Phase 2: The Execution/Typing Mode

Once planning is complete, you switch intentionally into typing mode.

The rules here are simple:

  • Follow the plan
  • Avoid big new decisions
  • Minimize context switching

Treat this like building from a blueprint.

1. Implement the plan, don’t redesign it

In this phase, you:

  • Translate your architectural decisions into code
  • Implement the interfaces and data models you already decided
  • Write tests according to the scenarios you planned

If you notice a major flaw in the plan, don’t secretly redesign everything on the fly. Instead:

  1. Make a small note (e.g., TODO: revisit architecture for X)
  2. Decide whether it’s a blocking issue or an improvement
  3. If it’s blocking, pause, switch back to planning mode briefly, then resume implementation

Keeping these modes separate stops your coding session from turning into an unbounded design spiral.

2. Protect your flow from context switching

In typing mode, your focus is on steady, high-quality throughput. To preserve flow:

  • Close or mute things that trigger big-picture thinking (roadmaps, Slack debates, docs)
  • Work from your plan, task list, or breakdown
  • Implement in small vertical slices that map to acceptance criteria

You’re aiming for:

  • Short feedback loops: write a bit of code, run tests, verify behavior
  • Visible progress: each slice moves you closer to “done,” as defined earlier

Because decisions are made, you’re not constantly pausing to think “What should this be called?” or “Where should this live?” You already decided.

3. Lean on your earlier investment

The planning phase may feel “slow” at first, especially if you’re used to diving straight into your editor. But in typing mode, you start to see the payoff:

  • Fewer rewrites because the architecture was thought through
  • Fewer defects because you anticipated edge cases
  • Faster code reviews because the intent is clearer

What looked like upfront “overhead” actually shortens the end-to-end delivery time.


Why Separating Thinking and Typing Works

This two-phase approach mirrors industry best practices found in:

  • Agile: user stories, acceptance criteria, and sprint planning
  • XP/TDD: design and tests guiding implementation
  • Architecture reviews: deliberate design decisions before building

By institutionalizing two distinct modes in your workflow — deliberate design/planning and fast, confident coding — you:

  • Reduce cognitive load by limiting context switching
  • Make better architectural decisions when your brain is in “big picture” mode
  • Get into flow during implementation, because you’re executing, not constantly rethinking
  • Deliver cleaner, more maintainable features in less calendar time

This isn’t about adding bureaucracy. It’s about choosing when you think and when you type, instead of trying to do everything at once.


How to Start Using Two-Phase Coding Today

You don’t need a process overhaul to try this. Start small:

  1. Pick your next feature and explicitly label two blocks on your calendar: “Planning” and “Implementation.”
  2. Planning block (no IDE)
    • Write the user story and acceptance criteria
    • Sketch the architecture and responsibilities
    • List technical/product/timeline risks
    • Define your “done” checklist
  3. Implementation block (no big decisions)
    • Follow the plan
    • Take notes on surprises or things to improve next time
  4. After you ship, retrospect briefly
    • What did planning catch that would have bitten you later?
    • Where did you still make big decisions while coding?
    • How can you tighten the boundary between the two phases next time?

With repetition, this becomes a habit. Your team starts to expect clear user stories, explicit designs, and focused implementation work.


Conclusion

When you blur thinking and typing, you slow yourself down with invisible friction: context switches, rework, and surprise risks.

By deliberately separating your work into a Planning/Thinking Phase and an Execution/Typing Phase, you:

  • Ship features faster end-to-end
  • Produce cleaner, more maintainable code
  • Reduce defects and rewrites
  • Work in a way that aligns with industry best practices

Invest time upfront in thinking mode. Your future self — and your codebase — will thank you when implementation becomes the easy part.

The Two-Phase Coding Session: Separating Thinking and Typing to Ship Cleaner Features Faster | Rain Lag