Question presented to candidate: "Your team wants to write real, fast tests for a 'register user' function without spinning up a real database for every test run, and separately, there's talk of possibly migrating from one database to another next year. What single change to how the code is structured would genuinely help with both of these, at once?"
What a strong answer should cover:
- The Repository pattern puts a real, narrow interface (create, findById, and similar methods) between business logic and the actual storage mechanism — business logic depends only on that interface's shape, genuinely unaware of whether it's backed by a real database, an in-memory store, or anything else.
- 📌 Verified, not assumed — the exact answer to the prompt's first half: a real
registerUserbusiness-logic function, completely unmodified, genuinely ran correctly against two entirely different real repository implementations — an in-memoryMap-backed one and a realnode:sqlite-backed one — producing correct, real results from both. This directly enables fast tests: swap in the in-memory repository for tests, genuinely no real database needed, with the identical business logic exercised either way. - 📌 Verified, not assumed — a direct, concrete confirmation of the decoupling: a real source-code check of the
registerUserfunction genuinely confirmed it contains zero references to"sqlite"or"Map"anywhere — the business logic doesn't merely happen to work with both; it has no way to know which one it's talking to at all. - This same, single structural change directly answers the prompt's second half too — a future migration to a different real database: only the repository implementation needs to change (a new class satisfying the identical interface) — the business logic, verified above to be genuinely storage-agnostic, needs zero changes at all.
- A precise answer names the honest scope: the Repository pattern adds a real layer of indirection — for a genuinely small, simple application with no real testing or migration pressure, that indirection is a real, sometimes-unnecessary cost; it earns its value specifically for the prompt's exact two scenarios (fast, real isolated tests; a genuine future storage-swap need) rather than being automatically justified for every project regardless of size.
Clarifying questions expected:
- "Is a real storage migration genuinely anticipated, or is this purely for the testing benefit?" — shapes how much the interface needs to anticipate future storage-specific capabilities beyond the current one's needs.
- "Should the repository interface be scoped narrowly to exactly what the business logic currently needs, or does it need to expose more of the underlying storage's specific capabilities?" — a real, practical interface-design trade-off.
Code / implementation expected: Yes — the identical, unmodified business logic function genuinely running correctly against two completely different real backing implementations, with a real source-code check confirming zero storage-specific coupling, is the concrete, convincing proof of exactly how the decoupling works and what it buys.