skip to content

A requirement says the confirmation must follow the charge, yet the design promises no order between them. What do you assert?

level: seniorimportance: nice to knowfreq 24%

answer

  1. Separate the requirement from the mechanism
  2. Ask what every permitted sequence must satisfy
  3. Assert the invariant, not the arrival order
  4. Look for a value that carries sequence
  5. A missing guarantee is a design finding

basics

~10 s

Assert the invariant every permitted sequence must satisfy — no confirmation stored without its matching charge, and the same settled balance either way — rather than an arrival sequence nothing in the design preserves.

solid answer

~50 s

Separate the requirement from the mechanism. "Must follow" is usually shorthand for a state property: *no customer is told a payment succeeded before it did*, or *no stored confirmation lacks a charge behind it*. Those hold under every sequence the design permits, so assert them and stop claiming an arrival order. Where sequence genuinely matters, look for something that **carries** it — a counter the producer stamps on each event, or a reference from the dependent event to its cause — and assert on that field, which is deterministic. Where the design orders events under one routing value, a scoped sequence assertion is fine, confined to that value. And if nothing carries the sequence at all, the honest output is a design finding plus the invariant case you can defend today; a test cannot manufacture a guarantee the system does not offer.

code

pseudocode · 14 lines
pseudocode
# requirement: "the confirmation must follow the charge"
# design promises: no order between the two events

key = new_unique_id()
produce(type: "charged",   key: key)
produce(type: "confirmed", key: key)

wait_until account(key).settled

# NOT asserted: which of the two was applied first
for c in confirmations(key):
    assert charge_exists(key, id: c.causeRef)
    assert c.causeSequence < c.sequence
assert account(key).balance == expected_balance

go deeper

for a junior

Recall that a case cannot create a guarantee the system does not offer. If nothing in the design keeps two events in sequence, an assertion about their sequence is a wish rather than a check.

for a middle

Explain the substitutes and what each needs: the invariant every permitted sequence satisfies, a counter or causal reference the events carry, and a sequence assertion confined to the routing value where order is genuinely promised.

for a senior

Be ready to push back on the requirement out loud and say what you would assert instead, including the case where the honest answer is that the guarantee is missing and belongs on the design's backlog rather than in an intermittent case.

for a principal

Own the escalation: decide when a sequence requirement justifies changing the design to carry order explicitly and when the cheaper answer is an invariant plus a reconciliation check, and be able to defend the cost of each to the teams on both sides.

## Separate the requirement from the mechanism "The confirmation must follow the charge" is a sentence about the business, not about a transport. It is usually shorthand for something narrower: *a customer must never be told their payment succeeded before it did*, or *the stored record must never show a confirmation with no charge behind it*. Those are properties of the settled outcome. They are true under every interleaving the design permits, and they can be asserted without any promise about arrival sequence. Start by asking the requester what a violation would look like to a person. If the answer is "the customer sees the wrong thing" or "the ledger is inconsistent", you have a state property. If the answer is genuinely "the second event must be processed after the first, and the design guarantees it", then you need a guarantee to test against — see the last section, because usually the design does not have one. ## Three substitutes, in order of preference | What you assert instead | What it needs | What it costs | |---|---|---| | The invariant every permitted sequence must satisfy | Nothing new; read the settled outcome | Reads the outcome once complete rather than watching it form | | A sequence value the events themselves carry | A producer-stamped counter or a causal reference field | A schema change if it is not there already | | Sequence, but scoped to where order is promised | A routing key the design orders by | Says nothing about anything outside that key | **The invariant.** Enumerate the sequences the design permits, and assert what is true in all of them: no confirmation without a matching charge; the balance after both events equals the same figure either way; a dependent record always references an existing cause. This is the strongest available assertion in most designs, and people undervalue it because it does not mention order — but a property that holds under every legal sequence is a *stronger* statement than one that holds under the sequence your run happened to get. **A carried sequence value.** If the events carry a counter stamped by their producer, or the later one references the earlier one by identifier, the sequence becomes a field you can read rather than a wall-clock accident. Then "the confirmation follows the charge" is an assertion about `confirmation.causeRef` pointing at a charge that exists, or about one counter being lower than another — deterministic, and independent of when anything arrived. **Scoped sequence.** Where the design really does order events under one routing value, assert sequence for events sharing that value and nothing else. Keep the scope visible in the case so the next reader does not widen it. ## What not to do - **Do not assert the sequence anyway and label the case intermittent.** That trades a design question for a maintenance cost and teaches the team that red sometimes means nothing. - **Do not assert your own production order.** The sequence in which the case emitted two events is not a property of the system; if the design does not carry it, no assertion can recover it. - **Do not tighten the deployment until the sequence holds** — one consumer instance, one producing path, no contention — and then claim the guarantee. You have asserted a property of a configuration nobody runs. - **Do not conclude that sequence is untestable.** It is testable exactly to the extent that something in the design carries it, and saying which part carries it is the answer the interviewer wants. ## When the honest answer is a design gap Sometimes the requirement really is a hard sequence guarantee, and the design offers nothing that carries it: no ordering key covering both events, no counter, no causal reference, two independent producing paths. No test can create that guarantee. Writing one anyway produces a case that is green when the system is lucky, which is worse than no case at all because it will be read as coverage. The right output is a finding, phrased in the design's own terms: *this requirement asks for a sequence the current design does not preserve; carrying a producer-stamped counter, or routing both events by the same key, would make it assertable.* Alongside it, ship the invariant case you can defend today, so the behaviour is not unguarded while the design question is decided. That is also the answer an interviewer is listening for. Anyone can write an assertion; the judgement being probed is whether you can tell a requirement that the system supports from one that it does not, and whether you say so before the assertion turns into an intermittent failure that somebody else inherits.

  • The team insists the sequence itself must be verified. What would have to change in the design first?
    Something has to carry the sequence: a counter the producer stamps on each event, a reference from the dependent event to its cause, or routing that pins both events into one ordered scope. Once one of those exists the assertion reads a field rather than a wall-clock accident. Until then, verifying sequence means verifying whichever interleaving the run happened to receive.
  • Why is an invariant assertion often stronger than the sequence assertion it replaces?
    Because it must hold under every sequence the design permits, not merely the one this run produced. That makes it fail for real defects and stay green for legal interleavings — the opposite of a sequence claim, which is silent about the defect and noisy about legal behaviour. It also survives an internal redesign of how sequencing is handled.
  • What do you write down when the guarantee is genuinely missing?
    A finding in the design's own terms: this requirement asks for a sequence the current design does not preserve, and a producer-stamped counter or a shared routing key would make it assertable. Ship the invariant case alongside it so the behaviour is not unguarded while the question is decided, and do not leave an intermittent sequence assertion in the suite as a placeholder.

saying these in an interview costs you the question

  • Asserts a sequence the design never promised in the first place
  • Treats the case's own production order as the processing order
  • Believes an invariant assertion is weaker than a sequence assertion
  • Accepts an intermittent ordering assertion instead of raising the gap
  • Concludes that asynchronous designs can never express sequence at all