Rubber duck debugging, in writing
The format of a good question turns out to be a debugging step that happens to be readable by other people.
There’s one sitting in a channel right now, half typed, with a stack trace pasted into the middle of it. I’m not going to send it. Somewhere around the part where I had to say what I expected to happen, I stopped, went and looked at the thing again, and my expectation was the bug.
That happens maybe a third of the time. It used to feel like effort I’d thrown away. I don’t think that anymore. The list of things you’re supposed to put in a question isn’t etiquette, or at least etiquette isn’t all it is. Every item on the list is a place where your own wrong assumption tends to be sitting. So you find out either way: you catch it while typing, or somebody else catches it in 4 minutes.
The duck can read
This is rubber duck debugging with better ergonomics. The duck works because saying a problem in order forces you to look at each assumption as you go past it, and one of them is wrong. Typing it works for the same reason, and the duck can answer.
It’s also the same shape as the halving I wrote up a couple of years ago. Get the thing to happen on demand, then rule out everything the working case and the broken case have in common. You usually have most of the answer before you’ve formed a hypothesis. Writing the question does that to your reasoning instead of to your code. Same halving, different input.
So the writing is doing work whether or not you send it, which is worth knowing when you’re sitting there deciding whether to bother anybody.
What are you actually trying to do?
Six things go in, and the first one is the one everybody skips.
What you’re trying to achieve. The goal, not the mechanism. “I want the section nav to track the page as you scroll” instead of “I’m trying to stop the observer firing twice.” Every so often somebody replies that you don’t need to do the thing at all, which is the best available answer and is one you cannot get if all you describe is the approach you already picked.
What you expected. This is where the wrong assumption lives. It’s often visible to a reader in a single line. Half the answers I give are some version of “your expectation is the bug.”
What actually happened, verbatim. The exact error text, copied, not paraphrased and not screenshotted if it’s text. Somebody can search a copied string. Nobody can search a PNG.
What you’ve already ruled out. Which saves them suggesting it, and signals you’ve done some work, and which you already have written down if you kept the questions file I keep going on about.
The smallest reproduction you can manage. Not the whole project. A person is far more likely to look at 15 lines than at a repository, and shrinking it is usually how you find it anyway.
And a specific ask. “Is there a way to tell my own scroll from the user’s?” is answerable. “Any ideas?” is not.
Anybody know much about IntersectionObserver?
That heading is the first of three openings that guarantee silence. I’ve written all three.
The meta-question asks people to volunteer before they know what they’re volunteering for, so the only safe move is to keep scrolling, because “yes” might turn out to cost you an hour. Ask the actual question. If somebody knows the answer they’ll say it, and if they don’t they’ve lost 8 seconds.
“It doesn’t work.” No reproduction, no error text, no statement of what you expected. To answer it the reader has to conduct an interview, which is several rounds spread over an afternoon, and most people won’t start.
Then the wall with no question in it. Four paragraphs of background, a screenshot of an entire screen, and no question mark anywhere. The reader has to reverse-engineer what you want from them. They’ll assume you’re thinking out loud.
None of the three is rude. They’re all just expensive, and the cost lands on somebody who was in the middle of something else.
Slide into my DMs
The fourth one isn’t about format at all. It’s asking in a direct message.
It halves your odds, because one person is either free or isn’t. It puts the entire cost on that person. And the answer vanishes into a private conversation instead of being findable by the next 4 people with the same problem, which was the thing I was going on about back when everything moved into channels. I’ll own the irony of ending up as the person arguing for more channel messages.
Am I allowed yet?
People get the math wrong in both directions.
The junior instinct is to keep going for 4 hours instead of admitting to being stuck, because asking reads as a status move. The senior instinct is to say “just ask sooner,” which is fine advice that doesn’t touch the reason anybody was doing it.
It’s worked for me to ask when you’ve run out of hypotheses. Not when it’s hard, and not on a timer. If you’re still generating things to try then keep going, because that’s the method working. When you’re down to changing things at random to see what happens, that’s the moment, and for me it usually lands somewhere between 30 minutes and an hour.
It’s also worth doing the math out loud once. An hour of yours against 5 minutes of theirs isn’t a close call. It’s the team’s hour either way.
My door is always open
Most of the responsibility here belongs to whoever answers, which is a thing I say a lot and don’t always live up to.
Answer in public. In the channel, not the reply that goes to one person, so it’s findable. I have turned up answers to my own questions from 3 years ago this way more than once, which is a strange feeling.
Answer the question, then say how you’d have found it. “There isn’t a way to tell them apart, and where I’d have looked is the note in the spec about what counts as a scroll.” The first half unblocks them today and the second half means they don’t need you next time, which is the actual job.
Never reply with “have you read the docs.” If the documentation had a findable answer in it we wouldn’t be here, and what that reply actually communicates is that the question was beneath you. Same for “just search for it.” If you don’t have time, say you don’t have time.
And give people a number. I’ve said this before and I’ll keep saying it. Telling somebody they should be asking you roughly once an hour for their first 2 weeks is worth more than any amount of “my door is always open,” because it converts permission into an expectation, and an expectation is something a person can meet.
4 minutes
The one I did send, a couple of weeks before the one I didn’t, about an IntersectionObserver doing exactly what I told it to:
The section nav highlights the wrong item for about a second after you click one. My guess is that the smooth scroll drags the page past every section on the way down, the observer treats each one as a real arrival, and the highlight walks down behind you and then settles. Dropping
behavior: "smooth"makes it stop, so I think that’s it. I’ve got a flag that ignores the observer until the scroll finishes and it works, but it feels like something I’d be embarrassed to explain in review. Chrome 138, the observer is insection-nav.jsaround line 40. Is there a way to tell my own scroll from the user’s, or is the flag what everyone does?
The answer, in 4 minutes, was that there is no way to tell them apart, the flag is what everyone does, and everyone hates it. Somebody else added that scrollend exists now and that I should go and look at the support table, which I did.
let ignoreObserver = false;
let settle;
link.addEventListener("click", () => {
ignoreObserver = true;
clearTimeout(settle);
settle = setTimeout(() => {
ignoreObserver = false;
}, 600);
});
That 600 is a number I picked by feel and it is still in there. scrollend would probably do the job properly and I haven’t gone back.
Nobody had anything better than the flag. It’s confirmation that I wasn’t missing something obvious, handed over by somebody who had already lost an afternoon to it. That’s most of what asking gets you. It’s worth a great deal and you only get it if the question can be answered at all.
The other one, still sitting there half typed, got me the same thing for free. I’d like to claim I do that deliberately now. Mostly I still start typing because I want somebody to come and rescue me, and then the rescue turns out to be the typing. I’ll take it in either order lol