Practical Coding Rounds/Extending an Existing Codebase

Reading for Conventions Before Writing a Line

Finding the existing seam your feature belongs in, matching the codebase's own patterns for naming, error handling, and layering, and why a minimal, convention-matching diff outscores a technically-more-elegant rewrite.

!!!2/5Theory: 20m1 problems

Why this round exists separately from machine coding

Machine coding starts you from an empty file — every design decision is yours to make. This round starts you from someone else's decisions, already made, and asks you to work within them. That's a deliberately different skill: the best possible design in isolation is the wrong answer here if it ignores what's already there. An interviewer running this format is watching for whether you treat the existing codebase as a set of constraints to respect, or as raw material to override — and the second instinct, however well-intentioned, reads as a real-world red flag, because it's exactly what makes a codebase hostile to the next five engineers who touch it after you.

Find the seam before you write anything

Every codebase has an implicit shape: a place new similar things go. Before writing a line, find the nearest existing analog to what you're about to add — a sibling class, a similar endpoint, a comparable validation rule — and read it in full. It answers questions you'd otherwise have to guess at:

  • Naming conventions. Is it getUserById or get_user_by_id or findUser? Matching the existing style isn't pedantry — inconsistent naming is one of the fastest ways to signal "this was bolted on by someone who didn't read the room."
  • Error-handling convention. Does this codebase throw exceptions, return Result/Either-style values, return null/None, or return an explicit error code? Introducing a second error-handling style alongside an established one is a common, easy-to-avoid mistake — pick whichever the codebase already uses, even if you'd have chosen differently starting from scratch.
  • Layering. Where does validation happen — at the API boundary, in a service layer, in the model itself? Where does the codebase draw the line between "business logic" and "data access"? Your new code should sit at the same layer its analogs sit at, not wherever seems locally convenient.
  • Test conventions. How are existing tests named and structured — one assertion per test, or a table of cases? Match that shape for your new tests too; a code reviewer scanning a diff notices immediately when the new tests look like they came from a different codebase.

Minimal diff as a feature, not a compromise

A common instinct under time pressure is to "clean up while you're in there" — rename a variable you find confusing, restructure a function you'd have written differently, fix an unrelated small bug you noticed along the way. Resist this specific instinct in this round. A large, sprawling diff is harder to review, harder to verify didn't break anything, and actively obscures the one change that was actually asked for. The professional habit this round is testing is the same one a real pull-request reviewer rewards: the smallest diff that correctly accomplishes the stated goal, with anything else you noticed called out verbally ("I noticed this validation looks incomplete, but that's out of scope for what was asked — want me to flag it separately or fix it now?") rather than silently bundled into your change.

When the existing conventions are genuinely bad

Occasionally the seam you find is itself poorly designed — a global mutable variable, a copy-pasted validation block that should be a shared function, an error-handling pattern you know is fragile. The strong move here isn't to silently fix it (scope creep) or to silently copy the bad pattern (propagating a known problem) — it's to name it out loud and ask how the interviewer wants you to handle it: "I see this pattern is repeated in three places already — should I follow it for consistency, or is improving it in scope here?" This single question demonstrates both that you noticed the smell and that you understand minimal-diff discipline is a default, not an absolute rule — and it hands the scoping decision to the person actually running the round, which is exactly where it belongs.

A concrete way to practice this deliberately

Clone a kata repo built specifically around "extend an existing, working system without a rewrite" — SupermarketReceipt-Refactoring-Kata is a good fit: a small, working checkout/pricing system where the practice task is adding a new discount or pricing rule. Time yourself, and before writing any code, spend the first few minutes explicitly answering the four bullet points above out loud (or in a scratch comment) — naming convention, error-handling convention, layering, test convention — before touching the implementation.

Further Resources (Optional)

Practice Problems

Interview relevancy:!!!Critical — must-have!!Important — highly recommended!Good to have~Niche — rarely asked