I was shipping a small update to one of my Android apps, the kind of release that's mostly a bug fix and a version bump. On my older laptop, a release bundle from a cold Gradle cache takes about eight minutes, most of it spent minifying and packaging. I started it, looked at the progress bar, and opened Slack "just while it runs".
There was a thread in a client channel about a deploy that had gone oddly the night before. I had opinions. I wrote a reply, then a longer one, then looked up a log to prove a point. When I came back to the terminal it was forty minutes later, and the build had failed in its second minute because the signing password wasn't set in that terminal session. A one-line fix. Then another eight minutes of waiting, during which I did, to my credit, nothing at all.
Fifty minutes for a ten-minute job, and the irony is that the Slack thread didn't need me either. That afternoon is why I now decide what I'll do during a wait before I press the button, not after.
That afternoon is why I now decide what I'll do during a wait before I press the button, not after.
A machine wait has a clock and an alarm
Builds, uploads, exports and CI runs share two properties that pull against each other. They end at a roughly predictable time, and they need your attention the moment they do, especially if they fail.
That combination is what makes them go wrong. The gap feels like permission to drift, so twenty minutes later you have neither a result nor progress on anything else. Or you overcorrect, start something demanding, and can't put it down when the pipeline turns red. I've done both, sometimes in the same week.
Waiting on people is a different problem. There's no completion sound and no estimate worth trusting, so I handle those with an explicit follow-up time in my status note rather than treating the silence as free time. Everything below is about machines.
Match the work to how cheaply you can drop it
The ranking that matters isn't how important the side task is. It's how much it costs to abandon it mid-sentence, because the machine will interrupt you, and you want that interruption to be cheap.
Drops instantly. Write the commit message or the release note. Update the ticket with what's about to ship. Add alt text, send the invoice you already planned, confirm a meeting time, answer the one message that needs one line. You stay inside the same mental model, or close to it, so returning costs nothing.
Pauses at a paragraph. Comments on one small review, or writing the verification notes for this same change. Fine for a long wait, as long as you wrote down what you're checking first.
Prepares the finish. Open the health check page, find the log query, pick the frames of the export you'll inspect, set up the test device. This is the most underrated option, because it turns the moment of completion into a calm checklist instead of a scramble.
Rest. A two-minute compile doesn't need to become output. Stand up, refill the water, look out of the window.
Doesn't belong here. A second feature in another codebase, a refactor, a research rabbit hole, a redesign of yesterday's slides, or a chat thread with opinions in it. When the run fails, you either ignore the failure or lose the thread you just built. My Slack detour belonged here. It only looked like a one-line reply when I opened it.
Write the menu before you press the button
Screenshot
Screenshot · 16:9a terminal waiting on a release build, progress still running and the signing step not finished, shows a machine wait you can leave only if the failure will call you back, dark terminal, 16:9, screenshot
What actually changed my behaviour was a short written list, made in the ten seconds before I start the process. Two or three items, matched to the expected length:
Two minutes: stand up, nothing else.
Ten minutes: update the ticket and draft the change note.
Forty minutes: the release notes, then one admin item.
Two hours: one real block of work in the same context, plus a break and a short admin batch.
Without the list, my attention goes looking for something to do and finds chat immediately. With the list, the side task is already chosen, and choosing was the hard part.
I don't trust the estimate exactly. Progress bars stall, CI queues grow on busy afternoons, and Gradle occasionally decides the daemon needs restarting. So I plan against recent runs rather than the best run I remember, and I pick work I can stop at the end of any sentence.
If machine waits are part of most of your days, keep a standing menu next to your daily plan, five to eight recurring options at most (structure a remote workday covers where that fits). Any item that keeps growing into real work comes off the list. It's a menu, not a backlog.
A two-hour pipeline, handled properly
On a client web project, the full pipeline on merge took around a hundred minutes: build, a long end-to-end suite, then a deploy to staging. Here's how a good version of that afternoon went.
13:15. Push and start the run. Before switching away, write the verification step in the ticket: "check the migration job log, then load the checkout page on staging and place a test order." Close the pipeline tab and set a reminder instead.
13:20 to 14:10. One proper block on the release notes for tomorrow's deploy. It's the ideal long-wait task, because it uses the context I already have and can stop at any paragraph.
14:10 to 14:20. Break, away from the screen. Glance at the pipeline once on the way back, not four times before then.
14:20 to 14:50. Admin batch: two invoice lines, a calendar decline, a short reply on a review. Nothing that takes more than fifteen minutes.
14:50 to 15:00. Reread the acceptance checks on the ticket and set up the screenshots folder so the staging review is one click.
15:00. Run finishes. Verify immediately using the step written at 13:15. If it's green, open the pull request. If not, read the first failure and classify it before touching anything.
None of those tasks matter in themselves. The point is that nothing in that timeline needed more than a sentence of warning to abandon at 15:00.
When the run goes red
I treat a failed run like a meeting that's just started: whatever I'm doing on the side stops. Then I read the first failure, not the last one, and sort it into one of three buckets:
Code. Something in this branch broke it. Fix it now, while the change is still fresh.
Flaky test. Rerun once, and write it down so the flake doesn't quietly become normal.
Infrastructure. A runner died, a registry timed out, a service was down. This is a blocker to report, not a project for the rest of the afternoon.
The third bucket is where afternoons disappear. I once spent most of a day trying to fix what turned out to be a full disk on a shared CI runner, which was neither my code nor my job to fix. A two-line message to the person who owned the runners would have taken five minutes.
A green result isn't the finish line either. Do the smallest relevant check straight away, while the context is still loaded. Green CI is not finished work goes into why a passing pipeline and a working deliverable aren't the same thing.
Uploads and exports that don't announce themselves
Builds at least make noise when they finish. Large uploads often don't. I moved a client's site to a new host once, and the backup upload over home broadband took about forty minutes with no notification at the end, just a browser tab that might or might not still be going.
For those, I set a visible timer for the expected length plus a margin, and stay with shallow work at the desk. The real risk with a silent upload is a failure at minute twelve that I only notice at minute thirty-five. Twenty-three minutes of nothing, plus redoing the upload. Leaving the room with no alert is exactly how that happens.
The same goes for app store uploads that sit in a processing state for a while after the upload itself finishes. The upload being done isn't the release being done. I keep that tab in the "check at a set time" pile rather than the "refresh every two minutes" pile.
What stays out of a wait, every time
A task that will still be open when the process finishes.
Anything that takes you away from the desk without an alert you'll actually notice.
Three long processes stacked on purpose so you never have to focus at all.
Treating a green notification as done without the check you wrote down.
Opening chat "just while I wait". That's where the accidental second project comes from, and in my case it came with forty minutes attached.
A plan that ignores waits pretends that eight hours of clock contain eight hours of typing. They don't, especially on projects with slow builds or long test suites. I now count the waiting into estimates for release days and anything that touches a full pipeline.
And when the waits become an excuse to hop between projects all day, the cost stops being small. It turns into the same tax described in the real cost of context switching, paid in eight-minute instalments. Machine waits are good for tidying, prepping and resting. Your next feature needs a proper block of its own (deep work for developers is where I'd put it), not the gaps between progress bars.
End of this piece
Writer
PrimedEcho
Independent notes on remote work, focus, and freelance practice. About this site.