DEV Community

Cover image for Debouncing Is an Interview Question: Build a Signal Filter You Can Explain
Karuha
Karuha

Posted on Originally published at aceround.app

Debouncing Is an Interview Question: Build a Signal Filter You Can Explain

Debouncing Is an Interview Question: Build a Signal Filter You Can Explain

A debouncer is not a delay stuck in front of a button. It is a small state machine with a contract: emit one transition only after an input has remained stable long enough. If you can explain that contract, test it against a noisy timeline, and name its latency trade-off, you have a strong embedded-systems interview answer.

The useful part of this exercise is that it scales beyond a push button. The same reasoning appears in reed switches, GPIO interrupts, noisy sensors, and any input where a physical signal can change faster than the application should react.

What does "debounce" actually promise?

Mechanical contacts rarely move from open to closed once. For a brief interval they may oscillate, producing a sequence such as:

0, 1, 0, 1, 0, 1
Enter fullscreen mode Exit fullscreen mode

If application code treats every sample as an event, one press can become several commands. A fixed sleep after the first edge may hide the symptom, but it does not state what the system accepts or rejects.

A better contract is:

  1. Keep a candidate state and the time it most recently changed.
  2. Reset the stability window whenever the sample differs from that candidate.
  3. Publish a transition only when the candidate differs from the reported state and has remained stable for the chosen window.

That gives an interviewer something concrete to inspect. The system does not claim that the electrical signal is clean. It explicitly converts a noisy sequence into a single application event.

A sample-to-transition timeline

Can you make the behavior executable?

You do not need a board to prove the logic. A tiny deterministic simulation lets you test the decision boundary before you wire it into an interrupt handler or polling task.

const assert = require("node:assert/strict");

function createDebouncer(stableMs) {
  let reported = false;
  let candidate = false;
  let changedAt = 0;

  return (sample, now) => {
    if (sample !== candidate) {
      candidate = sample;
      changedAt = now;
    }

    if (candidate !== reported && now - changedAt >= stableMs) {
      reported = candidate;
      return reported;
    }

    return null;
  };
}

function transitions(samples) {
  const debounce = createDebouncer(10);

  return samples.flatMap(([value, at]) => {
    const transition = debounce(value, at);
    return transition === null ? [] : [{ value: transition, at }];
  });
}

const events = transitions([
  [false, 0], [true, 1], [false, 2], [true, 4], [false, 7],
  [true, 10], [true, 15], [true, 20], [false, 30], [true, 32],
  [false, 37], [false, 47],
]);

assert.deepEqual(events, [
  { value: true, at: 20 },
  { value: false, at: 47 },
]);

console.log("debouncer timeline assertions passed");
Enter fullscreen mode Exit fullscreen mode

Run it with node debouncer.cjs. The first reported press arrives at 20 ms, not at the first high sample at 1 ms. The release is similarly delayed until 47 ms. The point is not that 10 ms is universally correct. The point is that the chosen policy has an observable result.

What should you say when the interviewer asks "why 10 ms"?

A strong answer does not say "because that is the standard debounce delay." There is no universal number.

Start with the device constraint: what does the switch or sensor specification say about bouncing, settling, or sampling? Then add the user constraint: how much extra response latency is acceptable? A 10 ms filter can be invisible for a human button but inappropriate for a fast encoder. A 50 ms filter may reject more noise but can make an interface feel sluggish.

That turns the conversation into an engineering trade-off:

Decision Benefit Cost
Shorter stability window Lower input latency More risk of publishing a bounce
Longer stability window More noise rejection Slower response
Polling Simple, deterministic test path Detection is limited by poll interval
Edge interrupt plus timer Faster first observation Requires careful shared-state handling

The table is more useful than memorizing a number because it gives you a way to adapt when the interviewer changes the constraints.

What failure cases are worth naming?

Most candidates stop after the happy-path press. The follow-up questions usually start there.

1. A press never becomes stable

If the candidate flips before the window ends, the debouncer should emit nothing. That is a legitimate outcome, not an error. In a real system, repeated instability may be diagnostic data: it can suggest a damaged switch, electrical noise, or an input sampled at the wrong threshold.

2. A long press should not repeat accidentally

The example emits a state transition, not a stream of "pressed" events. If the product needs auto-repeat, make it a separate feature with a repeat delay and cadence. Mixing repeat behavior into the debouncer is a common source of hard-to-test behavior.

3. Time can wrap

Microcontroller clocks wrap eventually. Do not compare timestamps with ad-hoc signed arithmetic. Use the platform's documented elapsed-time pattern and keep the counter width consistent. This is a small detail that shows you have moved from a demo to a deployment concern.

4. An interrupt and the main loop share state

If an interrupt records the latest edge while a main loop decides whether enough time has elapsed, identify the ownership boundary. The minimal safe design is often for the interrupt to record a timestamp and raw state while one task owns the published state. The exact synchronization primitive depends on the MCU and runtime, so state the assumption before promising lock-free safety.

How do you turn this into a two-minute answer?

Use a five-part narrative:

  1. Symptom: one physical action was creating multiple logical actions.
  2. Boundary: I required an input to remain stable for a measured window.
  3. Mechanism: I kept candidate state, last-change time, and published state separately.
  4. Proof: I replayed a bouncing press and release timeline and asserted exactly two transitions.
  5. Trade-off: a larger window filters more noise but adds latency, so I would choose it from component data and product expectations.

This shape works because each claim has evidence attached. It also makes a good live exercise: alter the sample sequence, alter the stable window, and predict the resulting events before running the code.

Where can AI help without replacing the reasoning?

AI is useful here as a rehearsal partner, not as a substitute for the hardware constraints. Ask it to generate adversarial timelines, then explain why each one should or should not yield an event. For embedded candidates, aceround.app — an AI interview assistant can help turn those test results into follow-up questions about interrupts, timing, and the trade-offs you actually made.

The answer still has to be yours. If you cannot explain why a stability window exists, what resets it, and what a test proves, an interviewer will find that gap quickly.

FAQ

Is debounce always a software problem?

No. Hardware filtering, pull resistors, shielding, and Schmitt-trigger inputs can all be appropriate. Software debounce is still valuable when the application needs an explicit event policy or when hardware alone cannot guarantee the required behavior.

Should I debounce inside the interrupt service routine?

Usually keep an ISR short. Recording raw state and time, then deciding in a task or main loop, is easier to reason about and test. The right design depends on latency requirements and the platform's concurrency model.

What is the most important test?

A timeline with several alternating samples followed by a stable period. Assert the number, value, and time of published transitions. A test that only checks one clean press does not exercise the feature you built.

Sources

Disclosure: AI assisted with outlining and editing. The technical example and its assertions were reviewed and executed before publication.

Top comments (0)