Debug Colander Output Bugs: Stray None, Nested Lists, and Empty List Versus Null
Company: Stripe
Role: Software Engineer
Category: Software Engineering Fundamentals
Difficulty: medium
Interview Round: Technical Screen
You are given a working copy of **Colander**, an open-source Python library that validates and deserializes data against a declared schema, into which bugs have been planted. Assume the exercise runs the library over a fixed set of inputs, records the results in an output file, and compares that file with the expected results. Three discrepancies are reported:
- `None` values appear in the recorded results, and the expected results contain none.
- Results that should be flat lists of strings are recorded as nested lists, such as `[s1, [s2, [s3, s4], s5], s6, s7]` where `[s1, s2, s3, s4, s5, s6, s7]` is expected.
- Equivalent cases are recorded inconsistently: some record an empty list `[]` and others `null`. Every such case must produce the same value.
For each discrepancy, find the code in the library that produces it, fix it there, and add a regression test.
### Constraints and Clarifications
- The expected results are the specification: do not edit them, and do not post-process the output file.
- Order within a recorded list matters.
- Colander represents "no value" with its own marker, `colander.null`, which is distinct from `None`.
### Clarifying Questions
- Is `null` in the recorded results Colander's `null` marker, or JSON `null` written by the recorder?
- Which representation is canonical for "nothing to report": the empty list or `null`?
- How deep can the nesting go, and can `None` appear inside nested lists?
- Can a recorded list legitimately contain other falsy values, such as an empty string?
### Part 1 — Stray `None` values
Find where a `None` enters a recorded result and remove it at its source.
```hint Walk back from one None
Take a single recorded `None` and find the first function whose return value already contains it. Ask what that function should return when it has nothing to contribute.
```
#### What This Part Should Cover
- How the `None` was traced to the function that produces it
- The fix, and why it belongs there rather than in the code that writes the file
- Not discarding legitimate falsy values
### Part 2 — Nested lists
Make every result that should be a flat list come out flat, in its original order, however deeply the lists are nested.
```hint Leaves and containers
Decide exactly which values count as containers to expand and which are leaves to keep. Try your rule on a string before you trust it.
```
#### What This Part Should Cover
- Where the nesting is created and where it is removed
- A flattening routine that preserves order and handles any depth
- Which types are expanded and which are kept as leaves
### Part 3 — `[]` versus `null`
Make equivalent cases record the same value when there is nothing to report.
```hint Two roads to nothing
Find the two code paths that produce these cases and pick one representation of "nothing" for both to return. Then check what that representation means to the rest of the library.
```
#### What This Part Should Cover
- The two code paths and the chosen canonical value
- An empty check that cannot match other values by accident
- Side effects of the change on code that already treats `null` specially
### What a Strong Answer Covers
- Traces each discrepancy from the recorded output back to the producing code before changing anything
- Fixes in the library rather than in the output, with the order of the normalization steps thought through for a list that holds only `None` values
- Exact checks: identity tests for `None` and for markers, explicit container types for flattening
- Regression tests for each discrepancy and for inputs that combine them
- Awareness of what `null` means elsewhere in Colander
### Follow-up Questions
- The nesting reaches thousands of levels. Does your flattening still work?
- A caller needs to tell "an empty list was supplied" apart from "no value". How do you reconcile that with Part 3?
- The same defects come from several methods. Do you fix every producer, or normalize in one place?
- What test would stop all three defects from coming back?
Overview: A debugging exercise in the Colander validation library, where recorded results contain stray None values, nested lists that should be flat, and an inconsistent mix of empty lists and null. It tests tracing bad output back to the code that produces it, safe list flattening, None handling and choosing one canonical empty value.
Read the full Stripe Software Engineer interview experience this question came from