Skip to main content
Zubin KhavarianZubin Khavarian
Editorial illustration of a friendly shaggy yak at a wooden desk, shaving its chin with a safety razor, beside a monitor, books, and a tiny bike shed.

Yak Shaving: Shave It, Stash It, or Skip It

· Last updated

You sit down after lunch to build a chat component. By five o’clock you’ve upgraded TypeScript, fixed the three type errors the upgrade caused, bumped the test runner because the new TypeScript broke it, and started rewriting your ESLint config because the test runner broke that. Every step made sense at the time. The chat component still doesn’t exist.

build chat component1:00 pmupgrade TypeScript1:20 pmfix 3 type errors2:05 pmbump test runner3:10 pmrewrite ESLint config4:30 pmchat component:0 linesthe yak
Every step made sense at the time.

That afternoon has a name.

Where the yak comes from

Carlin Vieri 🔗 coined “yak shaving” at the MIT AI Lab in the 1990s, borrowing it from a Ren & Stimpy episode. The meaning I find useful is a dependency chain. To do A you need B, to do B you need C, and a few links later you’re shaving a yak with no clear memory of how you got there.

People also use the phrase for busywork that lets you avoid the real task. That’s plain procrastination, and you already know what to do about it. The chain is harder to resist, because every link in it is real work.

It isn’t bike shedding

I mixed these two up for years. Bike shedding 🔗 comes from Parkinson’s law of triviality: a committee approving a nuclear plant spends two minutes on the reactor and forty-five on the staff bike shed, because everyone understands a bike shed well enough to have an opinion about it.

Once you picture them side by side, they’re easy to tell apart. A yak is usually one person going deeper. A shed is usually a group going wider on something small.

yakbike shedone person, going deepera whole group, going wider
A yak pulls one person deeper. A shed pulls a whole group wider.

They need different fixes, too. You scope a yak and put it somewhere safe. You end a shed with a decision: “The formatter wins. Next topic.” The rest of this post is about yaks.

Three questions before you shave

When you notice you’re about to step off the path, ask these before you touch anything.

Is it blocking? Can you ship the thing you sat down to build without it? “It would be nicer” doesn’t count.

Is it bounded? Can you say how long it’ll take, in minutes? “Let’s see” isn’t a number, and the yaks without one are the ones that eat days.

Is it the same story? A reviewer should be able to describe your pull request in one sentence. If the yak doesn’t fit in that sentence, it belongs in a different PR.

The answers sort every yak into one of three piles.

blocking?bounded?same story?skip itfile an issuestash itown branch, own PRshave itright now, in this PRyesyesyesnonono
Three questions, three piles.
  • Skip it when it isn’t blocking. File an issue and keep going.
  • Stash it when it’s blocking but too big for this PR, or it’s a different story. It gets its own branch and its own PR, and it usually lands first.
  • Shave it when it’s blocking, bounded, and part of the same story. Do it now and move on.

Most of the yaks I regret were skips that I talked myself into treating as shaves.

The same afternoon, replayed

Here’s the chat afternoon again, with the questions applied.

The TypeScript upgrade isn’t blocking. The new utility types are nice, but the chat component doesn’t need them. Skip it and file “Bump TypeScript.”

And that’s most of the afternoon handled. The type errors, the test runner and the ESLint rewrite all existed because of the upgrade. Skip the first yak and the rest of the chain never shows up.

build chat component1:00 pmupgrade TypeScript1:20 pmfix 3 type errors2:05 pmbump test runner3:10 pmrewrite ESLint config4:30 pmskipnever happenchat component:shippedkeeps its coat
The same afternoon with the checks applied. Skip the first yak and the rest never happen.

Tests still deserve a note, because they’re where this goes wrong most often. If chat’s own tests fail while you’re building it, that’s blocking and bounded, so fix them. If a test was already red on main, leave it alone. Fixing unrelated tests inside a feature PR means you can’t revert the feature later without reverting the fixes along with it.

The chat component ships. The yaks turn into a short backlog you can prioritize on purpose, instead of a pile you discover at 11pm.

Habits that keep yaks small

Write the yak down. A scratch file or a TODO at the bottom of the PR description takes ten seconds. A surprising number of yaks lose their urgency once they’re written down, because a lot of the pull comes from worrying that you’ll forget.

Get the diff off your branch. When a quick fix starts touching files unrelated to your feature, move it. git stash 🔗 parks uncommitted work, and git worktree 🔗 checks out another branch in a separate directory, so you can deal with the yak there without disturbing what you’re doing here.

Use a real timer. “I’ll give this twenty minutes” turns into an hour without one. When it goes off, don’t ask whether you’re close. Ask whether to stash it or spend another twenty.

Count the hops. The first detour is usually fine. The second is the warning sign, and by the third you’re doing archaeology. Counting hops is easier than judging how deep you are.

If you’re three hops in and haven’t touched the original feature, stop. Commit the detour to its own branch if it’s worth keeping, or stash it if it isn’t. Resist the urge to git reset --hard the afternoon away unless you know exactly which commit you’re resetting to.

When to shave anyway

Sometimes the questions say skip and you should shave it anyway.

It’ll block you next week. Flaky CI, a broken local dev setup, a type error you keep stepping around. Pay for it once, in its own PR, instead of paying a little every day.

You’re new to the codebase. Early on, following the chain is how you learn the system. That excuse runs out once you know your way around.

Otherwise, file the issue, ship the feature, and let the yak grow its coat back.

Stay in touch

Don't miss out on new posts or project updates. Hit me up on X for updates, queries, or some good ol' tech talk.

Follow @zkmake
Zubin Khavarian, Principal Front-End EngineerWritten by