Every team has it.
A pull request that’s “basically finished.”
A feature that’s “just missing a few small things.”
A task marked as almost done for the third week in a row.
It rarely looks like a problem. There’s no failing build, no red alerts, no production outage. And yet, this kind of work is one of the most effective ways to quietly destroy development flow.
Not by being wrong — but by never being truly finished.
Previous article in this category: https://codecraftdiary.com/2026/01/10/effective-code-reviews/
What “Almost Done” Really Means
In theory, almost done sounds harmless. In practice, it usually means one or more of the following:
- Tests are missing or incomplete
- Edge cases are known but postponed
- Naming or API design “can be improved later”
- Migration exists, rollback does not
- Documentation is optional… for now
None of these issues are dramatic on their own. That’s why they survive. The problem is that almost done work doesn’t behave like work in progress — it behaves like invisible technical inventory.
It sits in the system.
It consumes attention.
And it blocks flow.
The Illusion of Progress
Half-finished work creates a powerful illusion: movement without completion.
From the outside, things look active:
- PRs are open
- Commits keep coming
- Sprint boards show progress
But internally, the system is stuck.
Developers context-switch back to old code.
Reviewers repeatedly re-load the same mental model.
Small unresolved decisions accumulate into cognitive debt.
Nothing moves forward cleanly, because nothing is allowed to end.
Why It’s Worse Than Doing Nothing
A task that hasn’t been started yet is cheap.
A task that’s almost done is expensive.
Why?
Because almost done work demands continuous re-entry. Every return requires:
- Rebuilding context
- Re-evaluating past decisions
- Re-answering questions that should have been resolved once
This is not linear cost — it compounds.
The longer work stays in this state, the more expensive finishing it becomes. At some point, teams stop finishing at all. They work around it instead.
That’s when flow collapses.
Review Fatigue: The Silent Multiplier
Code reviews amplify this problem dramatically.
A PR that’s nearly ready but not quite there:
- Gets reviewed
- Receives feedback
- Gets partially updated
- Then stalls
When it comes back days later, the reviewer must start over.
Multiply that by several PRs and several developers, and you get review fatigue — not because reviews are bad, but because they never conclude.
At that point, reviewers stop caring about quality and focus on getting it merged. Standards drop, resentment grows, and nobody can quite explain why.
When Pull Requests Wait, Conflicts Multiply
One of the most visible symptoms of almost done work is a pull request that sits open for too long.
At first, nothing seems wrong. The code is there. CI is green. Review is “scheduled.”
Then time passes.
While the PR waits, the main branch moves on:
- New features are merged
- Refactors happen elsewhere
- Dependencies shift subtly
When the original author finally comes back, the PR is no longer just waiting for approval — it’s out of date.
Example: The PR That Was “Basically Ready”
Imagine a backend pull request that introduces a new endpoint.
The logic is implemented. Tests exist, but only for the happy path.
The author opens the PR and asks for review.
The review doesn’t happen that day.
Two days later, another feature touches the same service.
A small refactor is merged. Nothing dramatic.
When the original PR finally gets reviewed, it now has conflicts.
Tests fail because assumptions changed. The reviewer’s comments are no longer fully relevant.
What was a one-hour review becomes a half-day cleanup.
Nothing about the code was wrong.
It just waited long enough for the system to move around it.
That’s the real cost of “basically finished” work.
Merge Conflicts Are Not a Git Problem
At this point, conflicts appear. And teams often treat them as a tooling issue.
They are not.
Merge conflicts are a process failure.
They happen because work was allowed to remain unfinished long enough for the system around it to change. The longer a PR stays open, the higher the probability that it collides with unrelated changes.
This creates a feedback loop:
- PR waits for review
- Branch diverges
- Conflicts appear
- Author postpones fixing them
- Review is delayed again
The PR becomes heavier every day it remains open.
The Psychological Cost of Rebase Hell
Long-lived PRs don’t just create technical conflicts — they create psychological resistance.
Developers start associating the PR with:
- Painful rebases
- Repeated test failures
- Comments they’ve already addressed once
So they avoid it.
“This will take a full afternoon.”
“I’ll deal with it when I have time.”
That avoidance keeps the work in the almost done state even longer — exactly where it does the most damage.
Review Latency Is the Real Bottleneck
Teams often blame developers for not finishing work.
But in many cases, the real issue is review latency.
If reviews routinely take days:
- Developers stop prioritizing clean completion
- PR size increases (“If it takes days anyway…”)
- Conflicts become normal, not exceptional
At that point, the workflow trains people to leave things unfinished.
Short-Lived PRs, Short-Lived Problems
The solution is not hero reviewers or stricter rules. It’s shorter lifetimes.
A PR that:
- Is reviewed within hours
- Merged the same day
- Or explicitly rejected early
…does not accumulate conflicts, fatigue, or resentment.
It either finishes — or it dies quickly.
Both outcomes preserve flow.
Make Waiting Visible
One simple but effective practice is to treat waiting PRs as first-class problems.
For example:
- Highlight PRs open longer than 48 hours
- Treat “waiting for review” as a blocker, not a state
- Prefer reviewing over starting new work
When waiting becomes visible, it stops being normal.
Flow Breaks Where Work Waits
Conflicts, rebases, and stalled PRs are not isolated issues.
They are downstream effects of allowing work to stay almost done.
If you want fewer conflicts, don’t fight Git.
Finish work faster — or stop starting it.
Lean Has a Name for This
In Lean thinking, unfinished work is called inventory.
Inventory is dangerous because:
- It hides problems
- It ties up resources
- It creates false confidence
Software teams rarely think in these terms, but the parallel is exact.
Half-finished features are inventory.
Open PRs are inventory.
“Almost done” tasks are inventory.
And like any excess inventory, they slow the entire system.
Common Causes (That Sound Reasonable)
The most dangerous causes are the ones that feel justified:
1. Large Pull Requests
“Let’s do it properly in one go.”
Large PRs increase the chance that something remains unresolved — and once they stall, they tend to stay stalled.
2. Vague Definition of Done
If done isn’t explicit, almost done becomes acceptable.
Without a shared baseline (tests, docs, rollback, review passed), everyone uses their own internal standard.
3. Deferred Decisions
“We’ll clean this up later.”
“Let’s just ship it first.”
Later rarely comes.
Why Backend Teams Feel This More
Backend work has properties that make almost done especially toxic:
- Hidden coupling between systems
- Migrations that can’t be half-applied
- APIs that lock in contracts early
- Bugs that surface weeks later
A frontend workaround might be ugly but visible.
A backend shortcut is often invisible — until it explodes.
That’s why backend teams feel “slow” even when they work constantly.
They’re not slow. They’re stuck finishing yesterday’s almost-done work.
Practical Fixes That Actually Help
This is not about discipline or motivation. It’s about system design.
1. Define “Done” Ruthlessly
If it’s merged, it must include:
- Tests
- Review approval
- Clear naming
- Migration safety (if applicable)
Anything else is not done.
2. Reduce PR Size
Smaller PRs:
- Finish faster
- Get reviewed faster
- Fail faster
They either complete — or get killed early.
3. Ban “Almost Done” Language
This sounds extreme, but language shapes behavior.
Replace:
“It’s almost done”
With:
“It’s blocked because X”
Blocked work is honest. Almost done is deceptive.
4. Prefer Completion Over Throughput
Shipping fewer things that actually finish beats starting many things that don’t.
Flow comes from completion, not activity.
Finishing Is a Skill
Many teams optimize for starting work.
Few optimize for finishing it.
Finishing requires:
- Making decisions uncomfortable early
- Accepting “good enough” instead of perfect
- Closing loops deliberately
It feels slower at first.
Then everything accelerates.
Conclusion: Flow Is About Endings
Development flow isn’t created by speed, tools, or frameworks.
It’s created by ending things cleanly.
If your team feels busy but stuck, don’t ask how to move faster.
Ask how much work is almost done — and why it’s allowed to stay that way.
Because unfinished work doesn’t just wait.
It actively slows everything around it.

