Huh?
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.
The short way
WUTS in 47 seconds.
Something surprised you. Here’s the whole thing.
-
Wonder
Notice before you judge.
Instead of: deciding you’ve already found a problem.
-
Unpack
Understand before you prescribe.
Instead of: falling in love with your diagnosis.
-
Tinker
Learn before you commit.
Instead of: building the solution.
-
Share
Make the next encounter easier.
Instead of: merely telling people about it.
The test at the end: will this make the next encounter easier? That next person might be you.
While you’re here
I should admit that I’m not naturally good at this. Twenty-four years in 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 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.
Where it starts
Something doesn’t add up.
A test takes forty-five seconds. A customer uses the product in a way you didn’t expect. The abstraction you built yesterday already feels awkward. An agent keeps making the same mistake.
It could be code you wrote yesterday, a familiar tool behaving strangely, or a system your team inherited. What matters is that you noticed. That “Huh?” is a signal worth following.
Sometimes we shrug and get back to the ticket. Sometimes we start changing things before asking what surprised us.
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 that instinct. Wonder about what caught your attention. Unpack enough context to understand what you’re looking at. Tinker with something small enough to learn from. Share what you find.
Same curiosity. A little more discipline. More receipts.
One recurring condition
You’re missing some context.
Sometimes you weren’t there. Sometimes you were there and forgot. Sometimes everyone remembers the decision differently. Sometimes there was never a deliberate decision at all.
Unpack fills in the gaps: sometimes in a conversation, sometimes in a log from five minutes ago.
-
You wrote it.
Six months ago, this made sense. Apparently.
-
The team remembers it differently.
Same meeting. Three versions of what was decided.
-
The constraint changed.
The workaround stayed. The reason for it may not have.
-
The system grew around it.
The decision made sense locally. New callers brought new expectations.
-
Nobody quite decided.
One small convenience became the way everybody does it.
-
You inherited it.
The code arrived without the people, conversations, or notes that explained it.
The posture
A “Huh?” is not a verdict.
Noticing something weird doesn’t oblige you to fix it. It might be broken, inefficient, intentional, experimental, misunderstood, or perfectly fine.
A new abstraction might be solving a real problem. An old workaround might still protect a constraint. The strange behavior in your own code might be a tradeoff you’d make again today.
Or the constraint disappeared years ago. Or the new abstraction is getting in the way. Age and unfamiliarity are observations. Figuring out what they mean takes a little more curiosity.
The framework
Four disciplines. Not four steps.
Each one names a discipline, and the temptation that usually wins instead.
The first discipline
Wonder
Notice before you judge.
The temptation: deciding you’ve already found a problem.
Something made you stop. Get specific about what caught your attention.
- What did I expect? What happened instead?
- Have I seen this before? Who else runs into it?
- Am I seeing friction, or just something unfamiliar?
- What happens if we leave it alone?
A surprising result is enough to get curious. Start with something you actually noticed; don’t go hunting for things to fix.
Move on when there’s enough signal to justify getting curious about why.
Eight places the “huh?” shows up
-
Testing
This test fails. Sometimes.
The same test passes on the next run. Re-running it is becoming muscle memory.
What changes between those runs? Start by noticing the pattern you’ve learned to ignore.
-
Deployment
Twenty-two minutes to deploy.
Most of that time passes quietly. Everyone calls it normal. You’re curious where the minutes go.
Waiting and working can look remarkably similar from the terminal.
-
Your own code
I wrote this. Why does it do that?
Six months ago, you added this branch. Today its behavior surprises you.
Your name in the history doesn’t mean today’s version of you remembers the reasoning.
-
A new abstraction
We built this last week.
Explaining the new interface already requires a diagram and two exceptions.
Is there complexity the abstraction needs to represent, or did we add some? Worth wondering.
-
Product behavior
This customer takes the long way around.
They export a report, change one column, and import it again. Everyone else uses the form.
What are they trying to accomplish? Their detour might tell you something.
-
Developer experience
Why do I keep looking this up?
A command you run every Thursday still sends you back to the README. Everyone has their own wrapper.
Is the command awkward, the guidance hard to find, or the task different each time?
-
An inherited service
Why is this dependency still here?
The service relies on a library you rarely see anymore. You don’t yet know what it does.
Is it causing a problem, or is it simply unfamiliar to you?
-
AI agents
Why did the agent choose that example?
The agent keeps choosing a pattern the team no longer prefers. What makes it look like the right answer?
The environment may be offering a perfectly reasonable wrong answer.
The second discipline
Unpack
Understand before you prescribe.
The temptation: falling in love with your diagnosis.
Build enough context to understand what you’re looking at. Read the code. Reproduce the behavior. Trace callers. Measure it. Check the documentation. Talk to someone who sees a different part of the picture.
- What am I actually seeing? Can I reproduce it?
- What changed recently? What do the measurements show?
- What am I assuming about how this works?
- Who or what depends on it?
- What do the code, documentation, history, or other people tell me?
Sometimes history explains what you’re seeing. Sometimes the answer is in today’s logs, a framework convention, or a customer’s workflow. If you catch yourself gathering evidence for your favorite fix, ask what you’ve left out.
Move on when you understand the situation well enough to name what you still need to learn.
Eight ways to build context
-
Testing
Reproduce the slow run.
Run the forty-five-second test on its own and with its neighbors. Compare timings, setup, and external calls.
First find out what the time is buying. The assertion may be the quickest part.
-
Your own code
Read past the line you wrote.
Trace the callers. Compare the assumptions you made six months ago with the values arriving today.
The code may be unchanged while everything calling it has moved on.
-
Product behavior
Watch what the customer actually does.
Reproduce the detour. Ask the customer or support what happens before and after it.
The product shows you the clicks. The conversation may explain the job.
-
An unfamiliar framework
Check what the framework promises.
The new hook fires at an unexpected time. Read the documentation and compare a minimal example.
Your expectation may come from the last framework you used.
-
Operations
What changed since the last good deploy?
Compare logs, configuration, flags, and traffic. Ask what changed recently, including outside the code.
The useful history may be five minutes long.
-
An inherited dependency
Find what still depends on it.
Check callers, exports, integrations, and the incident notes that explain why this library was chosen.
An external system may read that output every Tuesday. Nobody here has ever met it.
-
Architecture
Put the implementations side by side.
Compare the three approaches: inputs, constraints, failure behavior, and what each makes easy.
Where do the requirements differ? Where did convention simply drift?
-
AI agents
Read what the agent can read.
Inspect repository instructions, examples, generated code, and documentation. Look for conflicting guidance.
The team’s preferred approach may exist mostly in conversations the agent never saw.
The third discipline
Tinker
Learn before you commit.
The temptation: building the solution.
Think of it as structured FAFO. What’s the smallest thing you could try that would teach you something? Add a trace. Remove one variable. Compare two approaches. Sometimes the whole result is information.
- What are we trying to learn?
- What’s the smallest experiment that could teach us that?
- What do I expect? What result would change my mind?
- Could observation alone answer the question?
- Am I accidentally turning the experiment into a project?
Once you’ve spent two weeks building your experiment, there’s a surprisingly good chance you’ll discover your experiment was brilliant. Experiments create prior art; today’s proof of concept becomes tomorrow’s example somebody copies.
Move on when you’ve learned enough to make a better decision than you could have before.
Eight experiments smaller than a project
-
Dependencies
Build the small branch first.
Try the likely replacement in a branch. What gets easier? What gets harder? Which assumptions surface?
Discovering six weeks of work for almost no improvement is a good outcome for a two-day branch.
-
Deployment
Time one path through the deploy.
Add timing around the slow steps. Try one change in staging and compare the result.
Keep the question small enough that the measurement can answer it.
-
Testing
Remove one variable.
Run the failure repeatedly with a fixed seed or a single worker. Change one condition at a time.
If the failure disappears, you’ve learned where to look next. You haven’t necessarily found the fix.
-
Developer experience
Wrap the awkward command.
Write one command for the task people keep looking up. Watch who uses it and what still needs explaining.
A tiny script can show you which parts of the workflow are actually shared.
-
A new abstraction
Try it on the next implementation.
Use the new approach once. Compare it with the direct version: code, explanation, review, and awkward edges.
Then decide whether it deserves eleven more copies.
-
Product behavior
Try one path behind a flag.
Try the alternative on a small, opt-in path. Watch where people pause and what they do next.
If the detour remains, the screen may not be what made the task awkward.
-
Infrastructure
Automate one step.
Automate the first step of the manual process and live with it for a week.
Some steps encode unwritten judgment. You tend to discover which ones by removing the wrong one.
-
AI agents
Change one source of context.
Change one instruction or example. Give the agent the same task again.
Did its behavior change? Now you’ve learned something about what’s teaching it.
The disciplines overlap. They send you backward. Unpacking often produces a better “Huh?” than the one you started with; a tinker sometimes reveals you never understood the constraint at all. That’s fine.
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.
-
Kept
You understand it now, and it still earns its place. Leave it alone.
-
Changed
You learned enough to improve it. Simplify it, fix it, remove it, standardize it, or tool around it.
-
Explained
The thing itself is fine. The missing piece was context. Leave that somewhere the next person will find it.
-
Observing
You need more evidence. Improve the signal, add instrumentation if it helps, and record what would make this worth another look.
-
Still unclear
You investigated and still don’t know. Record what you learned and the open questions. Not every investigation ends with certainty.
-
Tool it
The complexity is legitimate. A wrapper, script, or dashboard makes it easier for people to navigate correctly.
-
Standardize it
Several approaches accumulated. You’ve learned enough to make one path easier to find and follow.
The workshop
We’ve learned where to step around.
The command needs an extra flag. That test sometimes needs another run. Three implementations exist, but everyone knows which one to copy. Except someone joining the project tomorrow won’t.
Those coping mechanisms can make friction invisible. There’s always another feature, bug, or deadline, so we step around the rough edge again.
Agents encounter the same workshop without all those shortcuts. They may follow the outdated README literally, copy the leftover experiment, or miss a constraint that lives in someone’s memory.
Sometimes the agent is wrong. Sometimes the environment is giving it a perfectly reasonable wrong answer. That distinction is worth getting curious about.
As agents give us more capacity to build and change software, we can use some of it to improve the workshop itself. A clearer example, a wrapper command, a test, a better signal... something that makes the next encounter easier for everyone working here.
On discipline
Curiosity on its own is an appetite, not a virtue.
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. A few ways to get enough distance to notice again, without going hunting. Watch someone work on a normal task and don’t correct them. Write the letter to your replacement (“this is mostly a normal app, except...”) and compare it with what your teammates wrote. Imagine onboarding someone next week and walk their first day.
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 one good place to use WUTS. Wonder is noticing the fence without deciding it’s stupid. Unpack is finding out who built it and whether the field it guarded still exists. Tinker is leaning on it a bit before pulling it out. Share is leaving a sign so the next person doesn’t have to repeat the investigation.
What this is not
It isn’t a checklist, a ticket workflow, or four new statuses on a board. Nobody should be “in Unpack.”
It isn’t a mandate to change things. It also isn’t a mandate to leave them alone.
It isn’t a substitute for judgment. It’s a way of noticing when you’re about to skip the part that required some.
And one more time
Notice before you judge. Understand before you prescribe. Learn before you commit. Make the next encounter easier.
Origin
Where this habit came from.
I’m Robby Russell. I’ve spent most of my career around software that somebody else started. For twenty-four years I’ve run Planet Argon, a consultancy that mostly gets called when an application has been running for a decade and the team needs help making sense of it again. Mending, repairing, modernizing where it’s warranted, and fairly often talking a team out of the big rewrite they showed up asking for.
I host Maintainable, 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. It’s just as useful with code you wrote yesterday, a workflow you repeat every week, or a customer doing something you didn’t expect. I introduced it in a keynote at Rails World 2026.
The name is a bit of a joke. The reaction it’s built around usually isn’t “huh?”; it’s the other one. Hence the domain.
There’s a recording of the keynote coming. I’ll put the link here when it shows up.
Report back
What did you find?
Tried WUTS on something? Tell me where it led. A tiny experiment, some context you turned up, something you changed, or something you decided was better left alone.
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.
Is WUTS only for inherited or legacy software
No. Code you wrote yesterday, a new abstraction, a slow test, or a familiar command behaving strangely can all make you pause. Inherited software is one useful scenario. WUTS begins with noticing something, wherever it came from.
Isn’t this just FAFO
Same curiosity, a little more discipline. Messing with things is a useful way to learn. WUTS asks what caught your attention, what context you need, what small experiment would teach you something, and how you’ll share the learning. Tinker is structured FAFO.
Is this only for engineers
No. It’s for people who work on software. Engineers, product managers, designers, and support leads all notice friction, surprises, and mismatched expectations. Any of those can be the signal.
Isn’t this just an argument against ever changing anything
It isn’t. Plenty of WUTS cycles end in changing, removing, or replacing something. The point is to understand what you noticed before deciding it needs fixing. Weird might be broken. It might also be intentional, temporary, or perfectly fine.
Does it only apply to code
No. A confusing deployment, an awkward workflow, a surprising product behavior, and a repeating agent mistake can all be starting points. The signal matters more than which part of software work produced it.
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. You need enough understanding to make a better judgment.
Can I use this with my team
Sure, but please don’t make it a process. The moment there’s a Jira status called “Unpacking,” it stopped being curiosity. Pass the vocabulary around; keep the checklist out of it.
What about AI coding agents
An agent repeating the same mistake is a useful “Huh?” Sometimes it’s wrong; sometimes the environment makes the wrong choice look reasonable. Inspect what it can see, change one instruction or example, and try again. Keep what you learn somewhere future work can use it.