Run a 35-minute coding + narration mock
Implement a state reducer, amount parser, or merge function while explaining tradeoffs and tests.
Answer Strategy
For run a 35-minute coding + narration mock, start by stating the public contract before writing code: argument shape, return shape, mutation rules, error behavior, and whether work is synchronous, timed, cached, or cancellable.
A senior solution uses boring names for hidden state. If the function stores a timer, cache entry, listener, or in-flight promise, say who owns that state and how it is cleaned up.
After the baseline passes, harden the edge cases: empty input, repeated calls, invalid values, thrown callbacks, stable ordering, and memory lifetime. The reference below is written to be narrated line by line.
Reference Implementation: Memoize With TTL
This pattern covers the common interview utility shape: a small public API, private closure state, and tests for repeated calls.
type CacheEntry<T> = {
value: T;
expiresAt: number;
};
function memoizeWithTtl<TArgs extends unknown[], TResult>(
fn: (...args: TArgs) => TResult,
ttlMs: number,
keyOf: (...args: TArgs) => string = (...args) => JSON.stringify(args)
) {
const cache = new Map<string, CacheEntry<TResult>>();
return (...args: TArgs): TResult => {
const key = keyOf(...args);
const cached = cache.get(key);
const now = Date.now();
if (cached && cached.expiresAt > now) return cached.value;
const value = fn(...args);
cache.set(key, { value, expiresAt: now + ttlMs });
return value;
};
}Runnable Playground
Edit the implementation and run the tests directly in the browser. For system design questions, the playground focuses on the core state/data logic that the UI would call.
type CacheEntry<T> = {
value: T;
expiresAt: number;
};
function memoizeWithTtl<TArgs extends unknown[], TResult>(
fn: (...args: TArgs) => TResult,
ttlMs: number,
keyOf: (...args: TArgs) => string = (...args) => JSON.stringify(args)
) {
const cache = new Map<string, CacheEntry<TResult>>();
return (...args: TArgs): TResult => {
const key = keyOf(...args);
const cached = cache.get(key);
const now = Date.now();
if (cached && cached.expiresAt > now) return cached.value;
const value = fn(...args);
cache.set(key, { value, expiresAt: now + ttlMs });
return value;
};
}Testing Strategy
Convert the answer into observable behavior. In a mid-senior interview, say which behaviors are covered by unit tests, interaction tests, accessibility checks, and one browser smoke path.
test('utility caches repeated calls by contract key', () => {
let calls = 0;
const add = memoizeWithTtl((a: number, b: number) => {
calls += 1;
return a + b;
}, 1000);
expect(add(1, 2)).toBe(3);
expect(add(1, 2)).toBe(3);
expect(calls).toBe(1);
});Interviewer Signal
Interviewers are listening for judgment while you code.
Constraints
- Keep local, backend, wallet, chain, and user-visible state distinct.
- Name the product risk before naming the component.
- Tie the answer back to testing or rollout safety.
Model Answer Shape
- Implement a state reducer, amount parser, or merge function while explaining tradeoffs and tests.
- Use explicit ownership boundaries for state, data, and user intent.
- Describe how the UI prevents misleading certainty during pending or failed operations.
Tradeoffs
- Finance-grade UI should be conservative about certainty and optimistic about continuity.
- Local state improves recovery but must not pretend to be canonical business truth.
Edge Cases
- Refresh during pending work.
- Duplicate user intent.
- Backend, wallet, and chain disagree temporarily.
Testing And Proof
- State transition test.
- Reload recovery scenario.
- Accessible status and copy review.
Follow-Ups
- What would you log for support?
- How would you roll this out behind a flag?
Deep Finance Practice
This item has an authored finance specialization page with the original prompt, solution, and any available runnable harness.
Open legacy practice #622 ->