Practical coding rounds
Status: Complete. Last reviewed 2026-08-29.
These exercises test how a candidate scopes, communicates, implements, and verifies a bounded change. They are not puzzle drills. Before coding, restate the contract, expose assumptions, and choose a thin first verification. During the round, narrate meaningful trade-offs without turning every keystroke into commentary.
A useful round rhythm
Section titled “A useful round rhythm”Spend the opening minutes clarifying inputs, outputs, failure behavior, and the evaluation boundary. Build the smallest coherent path, run it, then deepen validation and design. If time runs short, leave working code and explain the next risk in priority order. Interviewers should distinguish incomplete scope from incorrect claims.
PHP — normalize webhook events (30 minutes)
Section titled “PHP — normalize webhook events (30 minutes)”Candidate brief: Implement normalizeEvents(iterable $rows): array. Each row should contain string id, ISO-8601 occurred_at, and type. Return unique valid events ordered oldest first. Duplicate IDs keep the earliest event.
Constraints: Do not mutate inputs. Reject or report malformed rows deliberately; do not silently rely on loose comparison. The result must be JSON-list shaped.
Fixtures: Include a duplicate with a different timestamp, a missing field, timezone offsets representing the same instant, and numeric-string IDs.
Evaluation dimensions: boundary typing, date comparison, stable array shape, explicit error policy, complexity, and focused tests.
Discussion and solution guide
Normalize into a typed value at the boundary, parse timestamps with failure handling, and key a map by an explicitly string ID. Replace only when the new instant is earlier, sort values by instant, and call array_values. Ask whether one bad row rejects the batch or produces a structured rejection list. Tests should cover equivalent instants and the chosen duplicate policy. See arrays and comparison and API idempotency.
SQL — reserve inventory safely (40 minutes)
Section titled “SQL — reserve inventory safely (40 minutes)”Candidate brief: Given inventory(sku, available) and reservations(order_id, sku, quantity), design the transaction that creates one reservation only when stock exists.
Constraints: Concurrent requests may target the same SKU; retrying the same order must not decrement twice. State the isolation and database assumptions.
Fixtures: inventory('A', 5); two concurrent orders requesting 4; a repeated request for the first order; an absent SKU.
Evaluation dimensions: invariant definition, atomic conditional update or locking, unique constraint for idempotency, affected-row checks, deadlock retry, and concurrency testing.
Discussion and solution guide
Put a unique constraint on the idempotency identity, use a transaction, and either lock the row before checking or issue an atomic UPDATE ... SET available = available - ? WHERE sku = ? AND available >= ?. Check the affected row count and insert the reservation consistently; handle uniqueness races and retryable transaction failures. Explain why a prior unlocked SELECT is unsafe. See the database guarantees reference and the executable SQL asset.
Laravel — tenant-scoped update endpoint (45 minutes)
Section titled “Laravel — tenant-scoped update endpoint (45 minutes)”Candidate brief: Implement an endpoint that updates a project within the authenticated user’s tenant.
Constraints: A project ID from another tenant must not be disclosed or modified. Validate the payload, authorize the action, and return a stable API shape.
Fixtures: authorized member, same-tenant unauthorized member, foreign-tenant ID, malformed payload, and missing record.
Evaluation dimensions: scoped lookup or binding, policy responsibility, validation order, mass-assignment boundary, response semantics, and feature tests.
Discussion and solution guide
Resolve the resource through a tenant-constrained query or custom scoped binding, then authorize the resolved model and update only validated fields. Decide deliberately whether foreign and missing resources are both 404. Test the HTTP boundary and database non-change, not merely the policy method. See tenant boundaries and routing/model binding.
Testing — confidence for a retrying job (30 minutes)
Section titled “Testing — confidence for a retrying job (30 minutes)”Candidate brief: Add tests for a job that charges a provider, records success, and retries timeouts.
Constraints: The provider may time out after accepting a charge. Avoid tests coupled only to framework call counts.
Fixtures: definite rejection, success, timeout-before-acceptance, ambiguous timeout-after-acceptance, and duplicate delivery.
Evaluation dimensions: observable invariants, fake boundaries, idempotency contract, retry classification, and one integration-level test.
Discussion and solution guide
First identify that retry safety cannot be proven without a provider idempotency key or reconciliation API. Test durable outcomes: one logical charge, recorded provider identity, and no success record on definite failure. A unit test can drive response categories; an integration test should verify transaction and queue behavior. See testing boundaries and retry-aware queues.
Debugging — rising worker memory (30 minutes)
Section titled “Debugging — rising worker memory (30 minutes)”Candidate brief: A queue worker’s RSS grows until restart. Build an investigation plan and make one justified code change from the supplied evidence.
Constraints: Do not assume a PHP heap leak. Evidence includes per-job heap, RSS, job type, tenant, query count, and a retained closure registry.
Evaluation dimensions: ranked hypotheses, discriminating measurement, long-lived state, allocator/RSS distinction, safe mitigation, and regression verification.
Discussion and solution guide
Correlate growth with job type and compare PHP-reported memory with RSS. Inspect retained references, static registries, container singletons, callbacks, and native buffers. Remove the demonstrated retention, add a repeated-job test or bounded profile, and retain worker recycling as a guardrail rather than calling it the root fix. See PHP process models and debugging scenarios.
Refactoring — conditional pricing policy (60 minutes)
Section titled “Refactoring — conditional pricing policy (60 minutes)”Candidate brief: Refactor a pricing function with customer, region, promotion, and date branches so a new promotion can be added safely.
Constraints: Preserve current behavior first. Avoid speculative frameworks and keep monetary rounding explicit.
Fixtures: Golden-master cases at boundaries, overlapping promotions, unknown region, and rounding-sensitive totals.
Evaluation dimensions: characterization tests, separation of policy from orchestration, precedence, naming, extension cost, and rollback-sized steps.
Discussion and solution guide
Capture current behavior, identify decision axes and precedence, then extract a small policy interface or ordered rules only where variation is real. Make money and time explicit dependencies. Add the new rule with focused examples and keep the refactor in reversible steps. See software design and the pricing example.