WUTSWonder · Unpack · Tinker · Share

There’s probably a story here.

A curiosity framework for people who work on software. Something made you go “Huh?” Here’s a way to follow that signal before deciding what, if anything, needs to change.

Illustration of Robby Russell, chin on hand, thinking “How curious...”
Me, noticing something. Not yet deciding anything about it.

The short way

WUTS in 47 seconds.

Something surprised you. Here’s the whole thing.

  1. Wonder

    Notice before you judge.

    Instead of: deciding you’ve already found a problem.

  2. Unpack

    Understand before you prescribe.

    Instead of: falling in love with your diagnosis.

  3. Tinker

    Learn before you commit.

    Instead of: building the solution.

  4. Share

    Make the next encounter easier.

    Instead of: merely telling people about it.

Our goal: Leave the workshop a little easier to navigate. For whoever, or whatever, comes through next.

While you’re here

I should admit that I’m not naturally good at this. Nearly three decades into working on software and I still catch myself reaching for the fix, mostly because fixing is the part other people can see. Sitting with “I don’t understand this yet” has always felt a little like something I’d get caught doing.

So some of this is a permission slip I wrote for myself. You’re allowed to spend time understanding something. You’re also allowed to learn by trying it. The useful question is what you’re trying to find out.

The rest of this page is those same four ideas with the examples and the arguments attached. Take your time with it. That’s sort of the whole point.

Illustration: a shrug and a raised eyebrow, thinking “I wonder...”
Still my least comfortable setting.

Where it starts

Something doesn’t add up.

That test used to take a couple seconds. Now it takes forty-five. A customer keeps exporting a CSV just to change one column and then uploads it again. And somehow we’ve ended up with three ways to do the same thing… with comments warning us away from two of them.

None of these necessarily need fixing. But… huh.

Illustration: a startled double-take, shouting “WTF?!”

Where it came from matters less than the fact that you noticed. Most of the time, we shrug and get back to whatever we were supposed to be working on. Other times, we start fixing the thing before we’ve stopped to ask why it caught our attention in the first place.

WUTS starts somewhere in between.

Same curiosity

A little more deliberate than FAFO.

Fuck around and find out is probably software development’s default curiosity framework. Change it. Run it. Poke it. See what happens. There’s real value in that. We learn by messing with things.

WUTS keeps the messing around. Just have some idea what you’re hoping to learn before you start poking at things… and maybe leave something useful behind when you’re done.

Illustration: two open toolboxes. The red one is labelled “FAFO” and holds a hammer, crowbar, scissors, dynamite and notes reading “Just ship it”, “Should be fine...” and “Thoughts & prayers”. The blue one is labelled “WUTS” and holds a magnifying glass, a notepad reading “Wonder Unpack Tinker Share”, a label maker, and tapes marked “Observe”, “Document” and “Leave a note”
Both boxes get opened. Only one of them leaves receipts.

One recurring condition

Something didn’t match what you expected.

Maybe the code is doing exactly what it was designed to do. Maybe the constraint changed, the original reason disappeared, or nobody quite decided anything in the first place. Whatever happened, something caught your attention.

Unpack fills in the gaps: sometimes in a conversation, sometimes in a log from five minutes ago.

Illustration: a puzzled look, thinking “Why is this here?”
A reasonable question. Even when I wrote it.
  1. You wrote it.

    Six months ago, this made sense. Apparently.

  2. The constraint changed.

    The workaround stayed. The reason for it may not have.

Illustration: a rusted light switch buried under strips of masking tape, hand-lettered “TEMP”, “Do not remove”, “Still needed?”, “???” and “Check: J.D. 4/12/21”
Still worth asking before flipping it.

The posture

A “Huh?” is not a verdict.

Noticing something weird doesn’t oblige you to fix it. It might be broken. It might be there for a very good reason. You might just be missing some context.

An old workaround might still be protecting a constraint. Or the constraint disappeared years ago and nobody told the workaround. Age and unfamiliarity are observations. Figuring out what they mean takes a little more looking. And if it’s Friday afternoon, leave the switch alone until Monday.

The framework

Four disciplines.

There’s no order to them and no finishing them. You’ll move between them, often backward.

The first discipline

Wonder

Illustration: one finger raised, thinking “Hang on.”
Me, not fixing anything yet.

Something made you stop. Before deciding you’ve found a problem, get a little more specific about what caught your attention.

  • What did I expect? What happened instead?
  • Am I seeing friction, or just something unfamiliar?
  • What happens if we leave it alone?

A few places this shows up

  1. This test fails. Sometimes.

    It passes locally, usually passes in CI, and then fails twice in a row when nobody has touched that part of the code in weeks.

  2. I wrote this. Why does it do that?

    You open a class you wrote six months ago and find a branch that looks completely unnecessary. Git blame isn’t going to save you. That’s your name on it.

  3. Did that dependency always do this?

    The upgrade was supposed to be boring. Now a method you’ve called for four years returns something subtly different when the collection is empty. Before pinning the old version forever… whaaa?

  4. This customer takes the long way around.

    They export the report, change a couple of values, then upload it somewhere else. Turns out this has been part of their Friday routine for years.

  5. Why did the agent choose that example?

    It keeps reaching for a pattern the team stopped using years ago. Annoying… until you realize it’s following the clearest example we left behind.

    The environment may be offering a perfectly reasonable wrong answer.

The second discipline

Unpack

Illustration: leaning in and pointing, thinking “Follow the history.”
Read the code. Check the logs. No, actually check them. Ask someone.

Now go looking. Read the code, reproduce it, check the logs, trace the callers… maybe talk to someone who sees a different part of the picture. What are you assuming about how this thing works?

The useful bit of context might be buried in Git history, or sitting right there in today’s logs, a framework convention, or a customer’s workflow. And if all the evidence seems to support the fix you already wanted to make, maybe look a little harder.

This is usually where the story shows up. Somebody had a reason. It might have been a good reason, a bad one, or a late-Friday one, and it may not have survived the three years since. Occasionally that somebody was me.

A few ways to go looking

  1. Reproduce the slow run.

    The job usually finishes in twelve seconds, but every few days it takes four minutes. Before rewriting it, find out what’s different about those four-minute runs.

  2. Watch what the customer actually does.

    Sit with them while they do the thing. The interesting part may be the spreadsheet they open halfway through, the second browser tab, or the step they forgot to mention because they stopped thinking of it as a step years ago.

  3. What changed since the last good deploy?

    That deploy changed more than you remembered. A dependency update, some configuration, a bunch of unrelated commits. Start pulling on those threads.

  4. Who still depends on this?

    The endpoint looks unused. Nothing in the app calls it, nobody on the team remembers it, and the logs are nearly empty.

    An external system may read that output every Tuesday. Nobody here has ever met it.

  5. Why are there three versions of this?

    They look redundant at first. Dig around a little and you start finding reasons for the differences… some current, some historical, and at least one nobody remembered.

  6. Read what the agent can read.

    The agent keeps using the wrong command in bin/. Before blaming the model, look around. Have we actually made the right command obvious?

The third discipline

Tinker

Illustration: a tiny screwdriver in a small box of wires, tongue out in concentration, thinking “Let’s see...”
One small experiment. Note the size of the screwdriver.

Think of it as structured FAFO. What’s the smallest thing you could try that might teach you something? Add a trace, remove a variable, try the supposedly better approach in a branch. You don’t have to keep any of it.

Once you’ve spent two weeks building your experiment, there’s a surprisingly good chance you’ll discover your experiment was brilliant (ask me how I know). Experiments also leave things behind. Today’s proof of concept has a way of becoming the example somebody copies next year.

A few small experiments

  1. Build the small branch first.

    You think replacing the homegrown authentication wrapper with the framework default will simplify everything. Try it in a branch before turning it into a project.

    Two days later you may discover it’s six weeks of work to delete forty lines of code.

    Great. Delete the branch.

  2. Try the upgrade somewhere disposable.

    The changelog says the upgrade is backwards compatible. Great. Upgrade it in a branch and run the ugly parts of the application against it.

    Reading another twenty GitHub issues probably isn’t going to tell you as much.

  3. Add the boring log line.

    You have three theories about why the job occasionally takes four minutes. Add enough instrumentation to find out which one is actually happening. You can delete the logging later.

  4. Remove one variable.

    The test fails every so often. Change one thing and run it again. Then another. See if you can get the weirdness to follow you.

  5. Do it both ways.

    Two implementations both sound reasonable and the team has been debating them for forty-five minutes. Build the smallest version of each.

    You may learn more from twenty lines of code than another hour of opinions.

  6. Change what the agent sees.

    The agent keeps reaching for the old pattern. Instead of rewriting the prompt for the sixth time, remove the stale example or give it one good example of the approach you actually want. Run the task again.

The fourth discipline

Share

Make the next encounter easier.

Illustration: holding out a sticky note that reads “Context today. Fewer mysteries tomorrow.”, thinking “The next person should know.”
Leaving a note. The next person might be me.

You learned something. Can you leave some of that understanding where the work actually happens?

A note might be enough. Or maybe the answer belongs in a test, wrapper, generator, lint rule, or skill. Hell, maybe you just need to delete the obsolete example that sent you down this rabbit hole in the first place.

A few ways to leave something behind

  1. Put the learning in a command.

    Everyone knows the import needs --skip-validation in staging and absolutely nowhere else. Stop making the next person remember that. Put it behind bin/import.

  2. Leave a test that explains the surprise.

    Two individually valid operations break when they happen in the opposite order. Once you finally understand why, leave behind the test you wish you’d had three hours ago.

  3. Leave the reason nearby.

    There’s a weird-looking timeout value that everyone will eventually be tempted to “fix.” If you just spent an afternoon discovering that a partner API closes the connection at 31 seconds, maybe leave that fact next to the 30.

  4. Remove what kept misleading you.

    The README still shows the old setup command. It mostly works… which is probably why nobody has removed it.

    What we leave behind still teaches.

  5. Improve what’s teaching.

    The agent keeps reaching for an API the team stopped using two years ago. Turns out there are fourteen examples of the old approach and one example of the new one.

    Maybe the agent isn’t the interesting part of this story.

Expect to bounce around. Unpacking something might leave you with a better “Huh?” than the one you started with. A tinker might send you back looking for context you missed. That’s fine.

Also, we’re roughly halfway through. Bio break if you need one; I did.

How it ends

More than one useful ending.

The point is to understand what you noticed and make a better judgment. Sometimes the whole outcome is simply: now we know why.

Illustration: adjusting my glasses while reading a TODO comment, thinking “Ohhh. That’s why.”
The clue was in my own comment. Naturally.
  • Kept

    Ah. Okay. Makes sense now.

  • Changed

    Well, now that we know…

  • Explained

    Nothing to fix here. Might be worth leaving some context for the next person.

  • Observing

    Not enough evidence yet. Keep an eye on it.

  • Still wondering

    ¯\_(ツ)_/¯

The workshop

We’ve learned where to step around.

The command needs an extra flag. That test sometimes needs another run. There are three implementations of the same thing, but we all know which one you’re supposed to copy.

Except someone joining the project tomorrow won’t.

I’ve had nearly three decades to get good at learning where the sharp edges are and then forgetting that I’m stepping around them. There’s always another feature, bug, or deadline.

Agents walk into the same workshop without all the shortcuts we’ve picked up. They’ll follow the outdated README, copy the leftover experiment, or miss the constraint that only exists in someone’s head.

Sure, the agent might be wrong. But maybe we gave it a perfectly reasonable wrong answer.

And if agents are giving us more capacity to build things, maybe we can spend a little of it cleaning up the workshop they’re building in.

Illustration: peering over the edge of a deep hole, thinking “Just a little deeper into the abyss.”
Me, not resisting the temptation. Note the absence of discipline.

On discipline

Curiosity, left alone, is just an appetite.

Curiosity without discipline becomes a rabbit hole, and I’m very capable of falling down those myself. The four disciplines are mostly there to keep “I wonder...” from turning into “I rewrote it over the weekend,” and to keep “I fixed it” from turning into the thing the next person has to wonder about.

Where the “Huh?” comes from

Long exposure to a system trains you to stop seeing it. You know the weird command needs an extra flag. You know which of the three examples you’re supposed to copy. You know that when the test fails that way, you just run it again.

Spend enough time somewhere and all of that starts to feel normal.

One way to notice again is to watch someone else work. Don’t help. Seriously. Give them a minute. Watch where they hesitate, what they try first, and which perfectly reasonable wrong turn they take.

Write the note you’d leave your replacement.

“This is mostly a normal Rails app, except…”

Keep going. The interesting stuff tends to show up after except.

One useful case

Chesterton’s fence, and what to do after you find one.

You probably know the parable: don’t tear down a fence until you know why it was put up. Good advice when the thing you’ve noticed protects a constraint. It even applies when you put the fence up yourself and have since forgotten why.

This is a good place for WUTS. Before pulling the fence out, find out why it’s there. Lean on it a little. See what happens.

Maybe it stays. Maybe it comes down. Either way, the next person shouldn’t have to start the investigation from scratch.

Illustration: a weathered fence post standing in tall grass, a hand-lettered wooden sign nailed to it reading “Ask me why.”
A familiar sort of “WTF?” Occasionally, I built the fence.

What this is not

It isn’t a checklist, a ticket workflow, or four new statuses on a board. Nobody should be “in Unpack.”

You might change the thing. You might leave it alone. Either way, you should understand what you’re making that call on.

Illustration: thumbs up, thinking “That’s one less riddle.”
That’s the whole ambition. One less riddle.

Origin

Where this habit came from.

I’m Robby Russell. I’ve been working in software for nearly three decades, much of it around systems somebody else started. I’ve run Planet Argon since 2002, helping teams maintain and evolve software they already depend on. Mending, repairing, modernizing where it’s warranted, and fairly often talking a team out of the big rewrite they showed up asking for. Somewhere in there I also created Oh My Zsh.

I host the Maintainable Software Podcast, where I’ve had hundreds of conversations about the art of maintaining and improving existing software, and I co-host On Rails for the Rails Foundation. A lot of those conversations circle the same thing: the engineer who understood why something was the way it was, and what it cost the team when nobody did.

WUTS is my attempt to name that habit so it can be taught, tried, and passed around. I introduced it in a keynote at Rails World 2026.

The name is a bit of a joke. The reaction it’s built around is rarely as polite as “huh?” Hence the domain.

I’ll add the keynote recording here when it’s available.

Report back

What did you find?

Tried WUTS on something? Tell me what caught your attention and where you ended up. Especially if you still don’t know what the hell was going on.

Or write it up somewhere of your own and send me the link. Those are usually the better ones.

Questions people ask

Is this just root cause analysis or the five whys with a new name

Those start after you’ve agreed something is a problem, and they aim at a cause. WUTS starts earlier, at the “huh?”, and it’s fine with ending in “this is intentional and here’s why.” Tinker also asks for an experiment before you commit, which most RCA formats skip. Use them together if you like; they’re not competing.

Isn’t this just FAFO

Same curiosity, a little more discipline. WUTS mostly asks what you’re trying to find out first, and what you’ll leave behind after. Tinker is structured FAFO.

How long should a WUTS cycle take

Often minutes. Adding one log line and waiting a week can also be a complete Tinker. If Unpack becomes a research project or Tinker becomes a rewrite, ask a smaller question.

Can I use this with my team

Sure, but please don’t add a new column to your Kanban board called “Unpacking”… because that’s not the point. Pass the vocabulary around; keep the checklist out of it.

What about AI coding agents

An agent repeating the same mistake is a useful “Hmm.” Agents are good at tripping over the things the rest of us learned to step around. Sometimes it’s wrong; sometimes the environment makes the wrong choice look reasonable.