Environment Variable Store with %KEY% Placeholder Substitution
Company: Google
Role: Software Engineer
Category: Software Engineering Fundamentals
Difficulty: medium
Interview Round: Technical Screen
Implement a small environment-variable store with template substitution. The setting is a shell startup file such as `.zshrc`, where a line like `export NAME="Tom"` defines a variable. After that, any string can refer to the variable as `%NAME%`, and parsing the string replaces each reference with the variable's value.
Write a class that stores the variables and parses strings, with this interface:
- `set(key, value)` stores a variable, overwriting any earlier value for the same key.
- `get(key)` returns the value stored for `key`.
- `parse(text)` returns `text` with every `%KEY%` reference replaced by the value of `KEY`.
```text
set("NAME", "Tom")
get("NAME") -> "Tom"
parse("Hello I'm %NAME%") -> "Hello I'm Tom"
```
### Clarifying Questions
- What should `parse` do with a reference to a variable that has never been set: leave `%KEY%` as written, replace it with an empty string, or raise an error?
- What should `get` return for a key that has never been set?
- How is a literal percent sign handled, for example in `50% off`? Is a lone `%` kept as it is, and is `%%` an escape for a single `%`?
- Which characters may a key contain, and are keys case-sensitive?
- If a value itself contains a reference such as `%OTHER%`, should it be expanded again, and what should happen if two variables refer to each other?
- Is loading `export` lines from a file part of the task, or is `set` the only way to define variables?
### Part 1 — Implement the store and the parser
Implement the class. State the rule you chose for each ambiguous case above before you code it.
```hint Scan instead of replacing per key
Think about what goes wrong if `parse` runs a string replace once for every stored key: when one value contains another key's reference, and when the text holds a percent sign that is not part of a reference.
```
#### What This Part Should Cover
- An explicit rule for each ambiguous case: unknown keys, lone and doubled `%`, key syntax, and re-expansion of values.
- A parser that handles references at the start, at the end and back to back, as well as text with no references.
- Time linear in the length of the input and the output.
### Part 2 — Dry-run test cases and edge cases
When you say the code is complete, the interviewer asks you to dry-run it on several test cases, including edge cases, before accepting it. Choose the cases, state the expected output of each under your rules, and trace the trickiest ones through your code line by line. Fix anything the trace exposes.
```hint Aim at the boundaries
Put percent signs at the first index, at the last index, next to each other, and without a closing partner, and after each one check which index your loop moves to next.
```
#### What This Part Should Cover
- Test cases spanning normal input, boundaries and malformed input.
- Expected outputs derived from the stated rules rather than from running the code.
- Finding and fixing any index, termination or tail-handling bug that the trace reveals.
### What a Strong Answer Covers
- Ambiguous semantics clarified before coding, with each rule isolated so it can change without a rewrite.
- A clean class: storage separated from parsing, and key validation in `set`.
- A correct single-pass parser that builds its output without quadratic string concatenation.
- Testing driven by the candidate, ideally before the interviewer has to ask for it.
### Follow-up Questions
- How would you add a loader that reads `export KEY="value"` lines from a file, and which malformed lines would you reject?
- How would you support recursive expansion, where a value contains `%OTHER%`, and detect a cycle such as `A` referring to `B` while `B` refers back to `A`?
- If `parse` is called millions of times on the same few templates, what would you precompute?
- How would the design change if several threads call `set` and `parse` concurrently?
Overview: Design a small environment-variable store with set, get and parse methods, where parse replaces %KEY% references in a string with stored values, as in a shell startup file. It tests string scanning, clear rules for unknown keys and stray percent signs, and the discipline to dry-run your own code on edge cases before calling it done.
Read the full Google Software Engineer interview experience this question came from