Code Quality Standards For Interviews

Interview code is judged differently from production code. The bar is:

  • Correct above all else
  • Readable — the interviewer should follow it without you explaining every line
  • Simple — the simplest solution that works, not the cleverest
  • Defensive only at boundaries — validate inputs once, then trust them
  • Testable — pure functions and clear data flow

Interview code is not:

  • Production-ready (no logging, no metrics, no retries unless asked)
  • Heavily commented (good names beat comments)
  • Premature-abstraction (no factory factories)
  • Defensive everywhere (validating inside hot loops is noise)

The Quality Dimensions

DimensionWhat “Good” Looks Like
CorrectnessHandles every edge case the problem allows
SimplicityNo clever tricks unless required for complexity
ReadabilityA peer can read it once and understand
Namingparent, visited, frequency — not p, v, f (except in trivial scopes)
ModularityHelper functions for distinct logical units
Boundary handlingEmpty/null/overflow checked once at the entry
No premature abstractionOne-time logic stays inline
No overengineeringDon’t build a config system for a 30-line problem
No hidden stateGlobals/singletons are red flags
Minimal mutationPrefer immutable returns where natural
No excessive clevernessOne-liners that need a paragraph to explain are anti-signal
Standard library useUse the language’s built-ins idiomatically
TestabilityLogic separated from I/O, deterministic

Bad vs Good Examples

Naming

Bad:

def f(a, b):
    r = []
    for x in a:
        if x > b:
            r.append(x)
    return r

Good:

def values_above(numbers, threshold):
    return [n for n in numbers if n > threshold]

Boundary Handling

Bad (validates in every iteration):

def sum_positive(nums):
    total = 0
    for n in nums:
        if nums is None or len(nums) == 0:  # checked every iteration
            return 0
        if n > 0:
            total += n
    return total

Good (validate once at the boundary):

def sum_positive(nums):
    if not nums:
        return 0
    return sum(n for n in nums if n > 0)

Excessive Cleverness

Bad (one-liner, hard to debug):

def has_duplicate(nums):
    return len(nums) != len({*nums}) if nums else False

Good (clear intent):

def has_duplicate(nums):
    seen = set()
    for n in nums:
        if n in seen:
            return True
        seen.add(n)
    return False

The good version also has the advantage of early termination — better complexity in practice.

Helper Functions

Bad (everything in one 50-line function):

def shortest_path(grid, start, end):
    # 50 lines of BFS, neighbor computation, distance tracking, all inline
    ...

Good (extract neighbor logic):

def shortest_path(grid, start, end):
    queue = deque([(start, 0)])
    visited = {start}
    while queue:
        pos, dist = queue.popleft()
        if pos == end:
            return dist
        for nxt in neighbors(grid, pos):
            if nxt not in visited:
                visited.add(nxt)
                queue.append((nxt, dist + 1))
    return -1

def neighbors(grid, pos):
    r, c = pos
    rows, cols = len(grid), len(grid[0])
    for dr, dc in ((-1, 0), (1, 0), (0, -1), (0, 1)):
        nr, nc = r + dr, c + dc
        if 0 <= nr < rows and 0 <= nc < cols and grid[nr][nc] != '#':
            yield (nr, nc)

Premature Abstraction

Bad (over-engineered for a single use):

class CounterStrategy:
    def count(self, items):
        raise NotImplementedError

class HashCounterStrategy(CounterStrategy):
    def count(self, items):
        d = {}
        for x in items:
            d[x] = d.get(x, 0) + 1
        return d

def majority_element(nums):
    counts = HashCounterStrategy().count(nums)
    return max(counts, key=counts.get)

Good:

def majority_element(nums):
    counts = Counter(nums)
    return counts.most_common(1)[0][0]

Mutation

Bad (mutates input):

def normalized(values):
    for i in range(len(values)):
        values[i] = values[i] / max(values)  # also recomputes max each iteration
    return values

Good (no mutation, single max computation):

def normalized(values):
    if not values:
        return []
    peak = max(values)
    return [v / peak for v in values]

Hidden State

Bad (global counter):

_call_count = 0
def fib(n):
    global _call_count
    _call_count += 1
    if n < 2:
        return n
    return fib(n - 1) + fib(n - 2)

Good (state passed explicitly):

@lru_cache(maxsize=None)
def fib(n):
    if n < 2:
        return n
    return fib(n - 1) + fib(n - 2)

Language-Idiomatic Code

You should write code that looks like it was written by someone fluent in the language. Examples:

Python

  • Use list/dict/set comprehensions where natural
  • Use Counter, defaultdict, deque, heapq, bisect
  • Use enumerate, zip, unpacking
  • Avoid C-style for i in range(len(x)) if you only need values

Java

  • Use enhanced for-loop where possible
  • Use Map.computeIfAbsent, Map.getOrDefault
  • Use Optional only where it fits the API; not for short-circuit logic
  • Prefer ArrayDeque over Stack (legacy)

Go

  • Prefer slices over arrays
  • Use for range for both index and value
  • Return errors explicitly; don’t panic in interview code
  • Buffered channels only when justified

C++

  • Use auto where it improves readability
  • Range-based for-loops
  • Prefer std::vector and std::unordered_map
  • Use emplace_back over push_back for non-trivial types
  • const references for non-trivial inputs

JavaScript/TypeScript

  • Use Map/Set (not {}/array hacks) when keys aren’t strings or order matters
  • const by default, let only when reassignment is needed
  • Avoid var
  • TS: prefer unknown over any at boundaries

Comments

  • Avoid: comments that restate what the code says (// increment i).
  • Prefer: comments that explain why — the non-obvious tradeoff, the invariant, the reason a less elegant approach was chosen.
  • Required: a one-line comment above any non-trivial recurrence/invariant. Example: # dp[i][j] = max profit with i transactions ending at day j.

Length

For most coding interview problems:

  • Easy: 10–25 lines
  • Medium: 20–50 lines
  • Hard: 30–80 lines

If your Easy is 80 lines, you’re overengineering. If your Hard is 200 lines, you’ve gone wrong somewhere — re-examine the approach.


Final Self-Review Checklist

Before saying “I’m done”:

  1. ☐ Function/variable names are meaningful
  2. ☐ No dead code, no commented-out blocks
  3. ☐ Boundary checks at the entry, not in the hot loop
  4. ☐ Helper functions for distinct logical units
  5. ☐ No mutation of input unless intentional and stated
  6. ☐ No globals introduced
  7. ☐ Standard library used idiomatically
  8. ☐ Indentation/formatting consistent
  9. ☐ Code I would be willing to send a colleague for review