Why this conversation
The take-home debrief is not graded on the code you sent. It is graded on what you do when someone shows you it is wrong. Defending, over-apologising, and "I would have fixed that with more time" all lose. Diagnosing out loud wins.
Dialogue
Tomasz: I ran two concurrent cancels against the same order id. Both returned 200 and the order book went negative. Talk me through that.
Jay: You're right, and I can see why. The cancel reads the order, checks it's open, then writes the cancelled state in a separate statement. Between the read and the write there's no lock and no version check, so two readers both see "open." That's a bug I should have caught; it's the same shape as a double-spend.
Tomasz: How would you fix it?
Jay: Smallest change: make the cancel a single conditional update, "set state to cancelled where id equals X and state equals open," and treat zero rows affected as "already cancelled," returning 409 instead of 200. That's atomic in Postgres without a transaction. If we later move the book in-memory, the same rule becomes a compare-and-swap on the order's version.
Tomasz: Why did your tests not catch it?
Jay: Because I tested the cancel path, not the cancel race. All my tests are sequential. The honest answer is that I didn't write a single concurrency test, and for a matching engine that's the wrong place to save time. If I were adding one now, it'd be a test that fires N cancels in parallel and asserts exactly one 200.
Tomasz: Anything else in there you'd flag before we do?
Jay: Two. The fee calculation uses floats; that should be integer minor units. And the matching loop is O(n) per incoming order because I used a list, which is fine for the exercise and wrong for production; a price-level map with FIFO queues is the standard fix. I chose to spend the time on the API and the tests instead, and I'd make that call again for a take-home, but I'd want those two fixed before anything real ran on it.
Key expressions
| Expression | 뜻 · 쓰이는 자리 |
|---|---|
| talk me through that | 그것을 설명해 달라 |
| I can see why | 이유가 보인다 |
| the same shape as | ~와 같은 모양(구조)이다 |
| smallest change | 가장 작은 변경 |
| zero rows affected | 영향 받은 행 0 |
| the honest answer is | 정직한 답은 |
| the wrong place to save time | 시간을 아낄 자리가 아니다 |
| anything you'd flag | 지적할 것이 있는가 |
| integer minor units | 정수 최소 단위(센트 등) |
| I'd make that call again | 다시 그렇게 결정하겠다 |
| before anything real ran on it | 실제로 무엇이든 그 위에서 돌기 전에 |