Beyond the Green Dots: Why the Best Software is Made Between Commits

We’ve all been there. You’re staring at a pull request with +1,200 lines of elegant, refactored Rust or TypeScript. The CI/CD pipeline is a sea of soothing green checkmarks. To an outside observer—or a non-technical project manager armed with a Jira dashboard—that commit represents about eight hours of high-intensity typing.

But you and I know the truth. The actual writing of that code took maybe forty-five minutes.

The other seven hours and fifteen minutes? That was spent staring at a whiteboard, pacing around the room, arguing with a senior engineer about API boundaries, reading RFCs, realizing your initial database schema was a normalization nightmare, and mentally simulating how your caching layer would behave under a thundering herd problem.

This is the core truth behind the recent industry-wide conversation sparked by the phrase: "Software is made between commits."

Today, I want to dive deep into what this means for us as engineers. In an era where AI assistants can spit out boilerplate at 100 lines per second, the value of a software engineer is rapidly shifting away from the act of typing code and toward the architectural design, critical thinking, and system modeling that happens before your fingers ever touch the home row. Let’s explore how to optimize for the space "between the commits" and why mastering this invisible phase is what separates junior devs from staff engineers.

The Fallacy of the High-Velocity Typist

For decades, tech companies have struggled with how to measure developer productivity. Because lines of code (LOC) or commit frequency are easily quantifiable, they became the default proxies for "work."

But optimizing for commit frequency is a local optimization that often leads to global system failure. When we focus purely on the artifact (the commit) rather than the process (the design), we introduce systemic risks into our codebases:

  • The "Code First, Think Later" Anti-Pattern: Diving straight into your IDE to solve a complex problem usually results in highly coupled, fragile code. You end up refactoring on the fly, building band-aids over bad assumptions made in the first ten minutes.
  • Architectural Drift: Without deliberate design time between commits, microservices begin to look like a distributed monolith, API contracts drift, and technical debt accumulates exponentially.
  • The AI-Generated Technical Debt Tsunami: With LLMs (like Copilot or Claude) integrated into our IDEs, the cost of generating code has dropped to zero. If your primary metric of success is commit velocity, you can now ship bugs at unprecedented speed.

The real engineering work isn't translating a feature spec into syntax. The real work is finding the simplest, most robust mental model for the problem, validating it, and then expressing it in code.

What Actually Happens Between Commits?

If we were to map the cognitive lifecycle of a solid feature implementation, the timeline looks less like a continuous stream of typing and more like a series of distinct, non-coding phases. Let’s break down what high-performing engineers are actually doing when they aren't writing code.

1. Mental Simulation and State Modeling

Before writing a single line of a stateful application, you have to model how data flows through your system. Let's say you're building a payment processing queue. You don't start by writing async function processPayment(). You start by mapping out the state transitions.


[Pending] ---> (Attempt Payment) ---> [Success]
     |                                   
     +-----> [Failed] ---> (Retry?) ---> [Retrying] ---> [Max Retries Exhausted]

Thinking through these state transitions "between commits" prevents edge-case bugs—like double-charging a user because of an unhandled network timeout—before they can ever be committed to git history.

2. The "Pre-Mortem" and Edge-Case Enumeration

Excellent software engineering is fundamentally pessimistic. Between commits, you should be asking yourself: "How will this fail?"

  • What happens if this API dependency latency spikes to 10 seconds?
  • What happens if the database connection pool is exhausted?
  • How will this system scale if our write load increases by 100x next Tuesday?

3. Designing for Readability and Delete-ability

Junior devs write code to show how smart they are. Senior devs write code that looks so simple it seems obvious. The time between commits is when you strip away the clever, over-engineered abstractions you initially thought of, replacing them with boring, readable, and—crucially—deletable code.

How to Optimize Your "Between-Commit" Time

If the most valuable part of software engineering happens when we aren't typing, how do we get better at it? Here are three concrete practices you can integrate into your daily workflow to maximize the quality of your pre-commit thinking.

1. Write RFCs (Request for Comments) and Design Docs

Before you open your IDE, open a markdown file. For any non-trivial feature, write a one-page design document. It doesn't need to be a bureaucratic nightmare. It just needs to cover:

  • The Goal: What problem are we solving?
  • The Proposed Architecture: High-level design (e.g., "We will use a Redis sorted set to handle rate-limiting").
  • Alternative Solutions Considered: Why didn't we use a token bucket algorithm instead?
  • Risks & Mitigations: How could this break, and how do we monitor it?

By forcing yourself to articulate your ideas in prose, you will instantly spot logical fallacies in your implementation plan that would have cost you days of refactoring if caught mid-commit.

2. Embrace "Readme-Driven Development" (RDD)

If you are building an open-source library, an internal API, or even a complex utility class, write the documentation first. Write the README.md showing how a consumer will use your API.

For example, if you are designing a rate-limiting middleware in Go, start by writing how the end-user will initialize it:


// This is what we want the end-user experience to look like.
// Writing this first forces us to think about developer experience (DX).
limiter := ratelimit.NewBucket(&ratelimit.Config{
    Rate:   100,      // 100 requests
    Window: time.Minute,
    Strategy: ratelimit.RedisBacking,
})

r.Use(limiter.Middleware())

If the hypothetical code in your README looks clunky, your implementation will be clunky. Fix the design in the docs before you write the Go code.

3. Leverage Whiteboard Architecture Diagrams

Don't jump straight into microservices. Draw your data flow. If you are working remotely, use tools like Excalidraw or Mermaid.js. For instance, visualizing a simple event-driven system architecture before coding helps clarify boundaries:


[Client App] 
     | (HTTPS POST)
     v
[API Gateway] ---> [Auth Service] (Validate JWT)
     | 
     | (Publish Event "user.created")
     v
[RabbitMQ Message Broker]
     |
     +---> [Welcome Email Consumer] ---> [SES/SendGrid]
     |
     +---> [Analytics Consumer] ---> [ClickHouse DB]

With this diagram clear in your mind, writing the individual services, setting up the AMQP channels, and defining the schema payloads becomes an exercise in translation rather than invention.

The AI Era: Why "Between Commits" Matters More Than Ever

We cannot talk about modern software development without addressing generative AI. Tools like Copilot, Cursor, and ChatGPT are incredible at generating code. They can write a boilerplate Express router or a SQL query with perfect syntax in milliseconds.

But AI cannot think "between the commits."

AI doesn't understand your business's unique domain model. It doesn't know that your legacy billing system has a weird race condition that requires a specific mutex lock. It doesn't know that your team plans to migrate from PostgreSQL to MongoDB next quarter.

In the AI era, the code itself is becoming a commodity. The architecture, the system design, the domain modeling, and the critical evaluation of trade-offs are the high-value assets.

If your value-add as an engineer is merely typing syntax, you are competing with tools that are faster, cheaper, and never sleep. But if your value-add is the structural integrity of the system designed in those quiet moments between commits, your skills are more valuable than they have ever been.

Conclusion

The next time you have a highly productive day where you only committed three lines of code, don't feel guilty. If those three lines were the result of hours of deliberate design, threat modeling, and simplification, you likely saved your team weeks of maintenance overhead and technical debt down the road.

Software isn't just a collection of text files we feed to compilers. It’s a living map of our mental models. Take the time to make those models robust. Slow down, step away from the keyboard, talk to your peers, and embrace the silence between the commits.

Over to You

What does your "between-commits" process look like? Do you use RFCs, physical whiteboards, or Readme-Driven Development? Let me know in the comments below, or share this article with your team's Slack channel to kickstart a conversation on how you measure real developer productivity!

Post a Comment

Previous Post Next Post