Skip to content
QSWEQB

Domain knowledge fundamentals

How an engineer acquires a business rather than absorbing it: what a company buys when it hires for domain experience, the thirty-day plan, ubiquitous language, where business rules hide, and why the legacy behaviour is a requirement. Fifty-seven items, fifteen worked through with a plan, a schema or a diagram.

57 questions

Go deeper on Working in a Domain

Why domain knowledge is a hiring criterion

What is a company actually buying when it hires for domain experience?

Fewer expensive misunderstandings, and a shorter distance between a business sentence and a correct implementation. Two engineers of equal technical ability will produce different systems in a specialist industry, because one of them asks what happens when the claim reopens and the other discovers it in month nine. The purchase is really insurance against a class of defect that testing does not catch, since a system can be entirely free of bugs and still encode the wrong rule — and that failure surfaces as an audit finding, a regulatory breach or a reconciliation that has been wrong for a quarter. The secondary thing being bought is credibility with the business, because a stakeholder who has to explain their own domain three times stops explaining and starts specifying solutions instead, which is where the interesting engineering judgement is lost.

Why is a domain misunderstanding more expensive than a technical mistake?

Because it is discovered late and by someone outside engineering. A technical mistake is caught by a compiler, a test or a monitor within hours, and the feedback names the defect. A domain mistake produces a system that runs perfectly while being wrong, so the loop closes when a regulator, an auditor or a customer notices — typically after the wrong behaviour has been applied to months of real transactions. The remediation is then not a fix but a fix plus a data correction plus an explanation to someone who is entitled to an answer. The multiplier is the accumulated data: a misread retention rule means every record written since the release is now non-compliant, and no deploy repairs that. This asymmetry is the whole reason domain fluency reads as a seniority signal rather than as trivia.

Show me a domain misunderstanding priced out.

The argument for domain investment is unconvincing in the abstract and obvious once the same defect is costed against a technical one.

Two defects, both shipped in the same release.

TECHNICAL DEFECT
  Cause      an unbounded query on the orders table
  Found by   latency alert, 40 minutes after deploy
  Blast      p99 checkout latency, one afternoon
  Fix        one index, one hotfix deploy
  Total      ~4 engineer-hours, no external exposure

DOMAIN DEFECT
  Cause      "cancelled" was implemented as a terminal state, because
             nobody said a cancellation can be rescinded within 14 days
  Found by   an operations analyst, 11 weeks later, when a customer
             asked why their reinstated policy had no cover
  Blast      2,300 policies cancelled and manually reinstated by
             creating NEW policies with new numbers and new start dates
  Consequences
             - cover gap of 1-6 days on 2,300 policies, some with
               claims in the gap
             - premium recalculated wrongly for all of them
             - regulatory reporting overstated new business by 2,300
             - the audit trail now says the customer bought twice
  Fix        model change, backfill, 2 claims reviewed by legal, a
             report correction, and an explanation to the regulator
  Total      ~14 engineer-weeks plus legal and compliance time

The arithmetic is not the point; the shape is. The technical defect was bounded by the time it took to notice, and noticing was automatic. The domain defect had no detector at all, because the system was behaving exactly as specified and every monitor was green.

The second thing to read from the ledger is that the remediation is mostly not engineering. Once wrong behaviour has been applied to real records, the cost is in reconstructing what should have happened, explaining it to people with authority, and repairing data that other systems have already consumed. A model change is the cheapest line in the block.

Notice where the requirement was: a single sentence nobody said out loud, because to the underwriting team a rescinded cancellation is Tuesday. That is the recurring pattern — the missing knowledge was not obscure to anyone who does the job, it was simply never worth writing down.

The line worth taking from this into an interview is that domain knowledge is a defect-prevention investment with a measurable counterfactual, not a cultural nicety. It buys you the question that would have been asked in week one.

What can a domain expert tell you that no document can?

Which of the documented rules are dead letters, which undocumented practice the business depends on, and what actually happens on the exception path. Documents describe the intended process at the moment someone had time to write it down. An expert can tell you that the approval step in the procedure has not been used since 2019, that two named customers have contractual terms overriding the standard rule, that the month-end figure is corrected by hand before it is published, and why. They can also tell you the frequency of each exception, which is the number that decides whether you automate it, tolerate it or refuse it — and frequency is almost never documented anywhere. The most valuable thing they hold is the reason behind a rule, because a rule you can only state is memorised, while a rule whose boundary you can find is understood well enough to design against.

Is four years at a bank the same as knowing banking?

No, and claiming it is the fastest way to be caught out. Tenure inside an industry produces domain knowledge only where the work forced you to ask why; otherwise it produces familiarity with one employer's workarounds. Engineers spend years inside a payments organisation building a notification service and never learn what happens after authorisation, because nothing in their week required it. The honest formulation in an interview is to name the surface you actually saw and the depth you reached: I owned the dispute case lifecycle and can talk about scheme deadlines and evidence retention, I never worked on settlement and would need to read. That answer is stronger than a vague claim to the whole industry, because the interviewer's next question will find the edge of your knowledge anyway and the only variable is whether you found it first.

When is domain knowledge not worth the investment?

When the domain is the product, and when depth would narrow you faster than it pays. A team building a database engine, a compiler or a developer tool has its hard problems in the technology, and time spent on an industry vertical returns little. The second case is a career one and worth stating honestly: deep expertise in one vertical, often in one jurisdiction, narrows your market to a small pool and decays when the rules change. Eight years in one country's pensions administration is highly employable inside that pool and awkward outside it. The protections are a portable craft alongside the domain, or a second domain acquired early enough that you own an acquisition method rather than one deep well — and the method is the transferable asset, since the second industry takes months where the first took years.

Learning a domain quickly

Show me a thirty-day learning plan with what to produce each week.

A learning plan without an artefact at each stage is a reading list, and a reading list produces fluent phrasing rather than understanding.

WEEK 1  Orient. Goal: know who the parties are and what each can refuse.
  read      one primary document about one core transaction - a message
            spec, a regulator's paper, a policy wording. Not a wiki page.
  do        get read access to the production schema and the ticket queue
  produce   a one-page map: parties, money, records, clocks, rules,
            exceptions. Deliberately incomplete.
  test      can you name every party in the transaction and what each
            one is allowed to refuse

WEEK 2  Trace. Goal: one real transaction, end to end, in the real systems.
  read      the schema of the two tables at the centre of it, plus every
            constraint, trigger and default on them
  do        pick ONE real identifier from production and follow it across
            every system it touches, including the ones nobody mentioned
  produce   a sequence diagram of the actual path, with the system of
            record named at each step and every handoff marked
  test      can you predict which system is authoritative for each field

WEEK 3  Interrogate. Goal: the exception path and the reasons.
  do        45 minutes shadowing an operator doing the job, then 45
            minutes of questions. Ask frequency, not just possibility.
  do        find the spreadsheet. There is always a spreadsheet.
  produce   a glossary of 20 terms in your own words, plus what breaks if
            each is misread. Circulate it for correction.
  test      before the operator answers an exception question, write down
            what you expect them to say. Are you right yet?

WEEK 4  Commit. Goal: be wrong in public, cheaply.
  do        present your map back to the business and let them correct it
  do        ship one small change on the exception path, not the happy one
  produce   a decision record for one domain rule you now rely on,
            including its origin and what would make it stop applying
  test      does an expert accept your description without adding a
            "well, except"

The load-bearing feature is that every week has an artefact somebody else can correct. Reading produces confidence at roughly four times the rate it produces accuracy, and the plausibly-wrong state is invisible from the inside — which is why the plan spends its weeks manufacturing opportunities to be corrected rather than accumulating notes.

The ordering matters more than the content. Documents first, because they are free and they teach you the vocabulary you need to ask a decent question; the expert's time is the scarce resource and it is wasted on definitions. The schema comes before the expert for the same reason: it tells you what questions are worth asking.

Week four is the part people skip. Shipping a change on the exception path is the cheapest possible test of a model, because the exception path is where the undocumented rules live, and getting it wrong there costs one ticket rather than a quarter.

The tests in the right-hand position are prediction tests, not recall tests. Being able to define a term is worthless as a signal; being able to guess what the operator will say next is the only reliable evidence that a mental model is doing work.

Why is the data model the fastest route to the business rules?

Because a schema is the one artefact that cannot lie about what the business has actually needed to record. Documentation drifts, people describe the intended process, and code is a mixture of rules and accidents — but a column exists because somebody once had to store that fact, and a constraint exists because somebody once suffered from its absence. Nullability tells you what is optional in real life. A unique constraint is a business identity claim. A status column's distinct values, taken from production rather than from an enum, are the actual lifecycle including the states nobody mentions. Two date columns where you expected one usually mean the business distinguishes when something happened from when it was recorded, which is a bitemporal requirement hiding in plain sight. The habit is to read the schema before the design document, then ask why each surprise exists.

Show me one transaction followed end to end across systems.

Pick one real identifier and follow it everywhere, because the architecture diagram shows the systems and this shows the business.

flowchart TD
    A[Customer submits a refund request<br/>in the self-service portal] --> B[Case created in the CRM<br/>and an SLA clock starts]
    B --> C[Eligibility checked against<br/>the order record in the ERP]
    C --> D[Operator approves it<br/>because it is above the auto-approval limit]
    D --> E[Payment instruction sent to the gateway<br/>as a separate transaction with its own id]
    E --> F[Ledger posting, then the<br/>daily reconciliation file]
    F --> G[Customer notified and<br/>the case closed in the CRM]

Four things fall out of this trace that no architecture document contained. The SLA clock starts at the first box, so the business measure of this transaction began before any engineering system had a durable record of it — which means a retry that recreates the case has just reset a contractual clock.

The gateway step carries its own identifier, and the refund therefore has two identities: a case number the customer quotes and a payment reference the finance team quotes. Every support conversation and every reconciliation break lives in the join between them, and if that join is not stored explicitly somebody reconstructs it by amount and date, which fails the moment a customer has two refunds for the same amount.

The reconciliation file is the step engineers omit and the business cares most about. The refund is not done when the gateway returns success; it is done when it appears on the settlement file and matches the ledger. That is where the real definition of complete lives, and it is usually a day later than the code believes.

The operator box is where the exception path enters. Ask what fraction of refunds cross the threshold, what the operator actually checks, and what they do when the ERP and the portal disagree — the answer to the last one is a business rule that exists only in that person's habits.

Do this trace with a real identifier rather than a hypothetical one. Hypothetical transactions take the happy path, because that is the only path anyone can describe from memory.

Why follow a single real transaction rather than read the architecture?

Because the architecture diagram is organised by system ownership and the business is organised by transaction, so the diagram hides exactly the handoffs where meaning changes. Following one identifier forces you through every seam: the field that gets renamed, the timestamp that switches timezone, the status that means something different on the other side, the system that turns out to be authoritative for a field you assumed you owned. It also surfaces systems nobody mentioned, which is common — a reporting extract, a legacy interface, a finance spreadsheet fed by a nightly file. The other benefit is that it produces a shared artefact quickly, since a trace is concrete enough that a business user will point at the wrong box immediately, whereas they cannot usefully review a box-and-arrow diagram of services.

What does shadowing an operator give you that a specification cannot?

The frequency and the workarounds. Watching someone do the job for an hour shows you which screens they never open, which field they always leave blank, where they keep a second window open to a system nobody told you about, and what they do when the answer is not in the system. It also gives you volume: the specification says a claim may be reopened, the operator tells you it happens about twice a week and always for the same two reasons. That number is what decides whether the case is automated, tolerated with a manual path, or refused. The last thing you get is the vocabulary as it is actually used, at speed, including the shorthand that never appears in a document — and hearing a term used in context is far more durable than reading its definition.

Which documents repay reading, and in what order?

Primary sources first, then the schema, then internal documentation, and treat slide decks as hearsay. A primary source is one the business did not write: a regulator's rulebook or consultation paper, a message specification, an industry standard, a contract or policy wording. These are precise because somebody is accountable for their precision, and they teach you the vocabulary in its correct sense. Then the schema, because it tells you what this organisation actually does within that space. Then internal documents, read as evidence of what somebody believed on the date they wrote it — check the date first, and check it against the schema. Runbooks and support macros are underrated, because they describe the exception path in operational detail that no design document contains. Architecture decks are last, since they describe intentions.

How do you tell understanding from fluent phrasing?

By testing prediction rather than recall, because the two states feel identical from the inside and fluency arrives first. Three cheap tests. Before an expert answers a question about an exception, write down what you expect them to say; if you are consistently right, your model is doing work. Second, explain why the business does something inconvenient — a delay, a duplicate form, a manual check — in terms of a constraint rather than in terms of legacy, because real understanding usually reveals that the inconvenient thing is load-bearing. Third, name what would have to change for a rule to stop applying. A rule you can only state is memorised; a rule whose boundary you can locate is understood. The failure this guards against is the engineer who talks convincingly for ten minutes and collapses on the eleventh.

How do you learn a domain without stalling delivery in the meantime?

By attaching the learning to work you are already doing, and by being explicit about what you do not yet know. Ship on the happy path early to prove the environment and earn the right to ask questions, then take a ticket on the exception path deliberately, because that is where the domain lives and the tickets are small. Write your assumptions into the pull request or the design note, phrased as statements a business reader can contradict — "I have assumed a cancellation is terminal" — which converts your ignorance into a review item somebody can catch for a minute's effort. What does not work is a reading month before contributing, because you cannot tell which knowledge matters until you have hit a decision that needed it, and the organisation reads the silence as slow onboarding.

The language of the business

Why is the glossary an artefact worth owning?

Because it is the cheapest defect prevention available and nobody wants the job, which makes it a visible contribution a new joiner can make in week three. A glossary is not a dictionary; its value is in recording which team means what, where two definitions conflict, and what breaks if the wrong one is used. Owning it also gives you a legitimate reason to interview everyone — you are not asking for help, you are collecting definitions — and it makes your own ignorance productive. The failure mode to avoid is a glossary of tidy one-line definitions, which reads as complete and prevents nothing. The entries that earn their keep are the contested ones, and the discipline is that every term is attributed to the person or team who gave it, with a date, because definitions move.

Show me a glossary entry done properly.

One line per term prevents nothing. The entries that pay for the glossary are the contested ones, recorded with the conflict intact.

TERM        Active
STATUS      CONTESTED - do not use unqualified in any interface

Definition given by Sales Operations, 12 Mar 2026 (K. Mensah)
  A customer is active if they have a signed contract that has not
  reached its end date. A customer who has stopped paying is still
  active until the contract lapses. Used for pipeline and renewals.

Definition given by Billing, 14 Mar 2026 (R. Doyle)
  A customer is active if we successfully collected in the current
  cycle. A failed direct debit makes them inactive that same night.
  Used to decide whether to raise the next invoice.

Definition in the code (customers.is_active, added 2019, no ADR)
  Set true on contract signature. Set false by the dunning job after
  three failed collection attempts. So it is Billing's meaning, with
  a 45-day lag, sitting in a column Sales reports read.

THE DEFECT THIS CAUSED    INC-4471, 8 Jun 2026
  The renewals campaign selected WHERE is_active = true and excluded
  312 customers whose direct debit had failed but whose contracts had
  11 months left. They were never contacted about renewal. Two churned
  and cited "you stopped talking to us". Nobody was wrong: the query,
  the column and both definitions were all internally consistent.

RESOLUTION
  The word "active" is banned from new interfaces and reports.
  Replaced by contract_status - in force, lapsed, terminated - owned
  by Sales Operations, and collection_status - current, in arrears,
  suspended - owned by Billing. The old column is deprecated with a
  view for the four reports that still read it.

The entry is long because the conflict is the content. A glossary that had said "Active: a customer with a live contract" would have looked complete, satisfied a documentation audit, and prevented nothing — because the problem was never that the word was undefined, it was that it was defined twice.

The code section is the part that makes it actionable. A column name is a definition with more authority than any document, because queries are written against it by people who never read the glossary, and this one silently exported one department's meaning into another department's reports.

Read the resolution carefully: the fix is not to choose a winner. Both meanings are legitimate and both are needed, so the resolution splits the word rather than arbitrating it. Choosing one would have forced whichever team lost to keep the old meaning informally, which is the same defect with worse documentation.

The defect reference is what gives the glossary standing. Entries linked to incident numbers get read; entries that read as tidying do not, and an uncontested glossary is quietly ignored within a quarter.

What is ubiquitous language, and what does it change in the code?

It is the practice of using the business's own words, in their business meaning, everywhere — in conversation, in the model, in class and column and event names — so that a discussion about the code is simultaneously a discussion about the business. What changes concretely is that translation disappears. Without it, every conversation crosses a mapping layer that lives in the heads of two or three people, and every defect can enter at the crossing: an engineer hears "settlement", implements the payment movement, and the business meant agreeing the amount. With it, a business expert can read a domain event name and tell you it is wrong. The cost is real and worth naming: you must refuse convenient generic names like data, status and process, and you must change names when the business corrects you, which means renaming in code you thought was finished.

Show me how one word used two ways becomes a production defect.

The failure never appears at the boundary where the word changed meaning. It appears two systems later, as a business consequence.

sequenceDiagram
    participant S as Sales system
    participant O as Order service
    participant B as Billing service
    participant W as Warehouse
    S->>O: Order confirmed - the customer accepted the quote
    O->>B: Publish OrderConfirmed
    B->>B: Raise the invoice, because confirmed means payable here
    O->>W: Request stock allocation
    W-->>O: No stock, order cancelled
    B-->>S: Invoice already issued, so a credit note is needed

Nothing in this sequence is a bug. Every service did what its own model said, every message was delivered, every log line is clean, and the defect arrives as an accounting query about credit notes six weeks later.

The ambiguity is in one word. To Sales, confirmed means the customer has agreed to buy — a commercial milestone, reversible until fulfilment. To Billing, confirmed means the obligation exists and is payable, which is an accounting event that is not supposed to reverse. The event name carried the first meaning and the consumer applied the second, and because the word was shared nobody noticed that a translation had happened.

The specific damage is that Billing has recognised revenue for an order that will not exist. Reversing it is not a delete: a credit note is itself a legal document with its own numbering, its own tax treatment and its own audit visibility, so the cheap fix in code creates a permanent artefact in the finance system.

Two fixes are available and only one is durable. The tactical one is to make Billing wait for a later event, which works until the next consumer makes the same assumption. The structural one is to admit that these are two bounded contexts and name the events for what each context actually means — QuoteAccepted from Sales, OrderPayable raised only after allocation — so the word never crosses the boundary carrying an implied meaning.

The interview point is that this class of defect is invisible to testing. Each service's tests pass against its own understanding, and the contract test, if one exists, asserts the schema rather than the semantics.

Show me the same requirement in business and engineering vocabulary.

Translation runs in both directions, and the errors live in the gap between the two columns.

Requirement as the business states it, and as it must be implemented.

BUSINESS                            ENGINEERING
----------------------------------  ----------------------------------------
"A customer can cancel within       Cancellation window = 14 calendar days
 fourteen days and get their        from the contract start date in the
 money back."                       customer's local timezone, not UTC and
                                    not the record's created_at. Refund is a
                                    new ledger transaction, not a reversal.
                                    Original transaction is immutable.

"The refund should be the full      Full premium minus any days of cover
 amount."                           already provided, computed on whole
                                    days, rounded to the customer's
                                    advantage. If a claim was made in the
                                    window, the amount is zero and the
                                    cancellation still stands.

"It should happen straight away."   The cancellation is effective on
                                    acknowledgement. The money moves on the
                                    next settlement run, up to 3 working
                                    days later. Two different clocks, and
                                    the customer must be told both.

"Obviously we keep a record."       The record is immutable, retained 7
                                    years after the contract ends, and must
                                    show who cancelled, on whose authority
                                    and what the customer was told. Deletion
                                    on request does not apply to it.

WHAT EACH COLUMN GETS WRONG ALONE
  business only     "straight away" and "full amount" are both false, and
                    the claim-in-window case is not mentioned at all
  engineering only  a spec written from column two alone will define the
                    window from created_at, in UTC, because that is the
                    column that exists

The point of laying it out this way is that neither column is the requirement. The business sentence is a summary of an intent, correct at the level it is meant to operate; the engineering column is a set of decisions, most of which the business would recognise and one or two of which they would reject.

Look at what the left column omits rather than what it gets wrong. "Obviously we keep a record" is four words carrying an immutability requirement, a retention period and a conflict with the deletion right — and it is stated as an aside because to the business it is not a requirement at all, it is how the world is. The omissions are always in that category.

The rounding line is the one to volunteer in an interview. "Rounded to the customer's advantage" is a rule an engineer would never invent, would implement as banker's rounding by default, and which exists because the alternative generates complaints that cost more than the pennies. Asking which direction to round is a small question that signals you know money has a domain.

The two-clocks row is the recurring shape across every domain: the business event and the money movement happen at different times, and describing them as one thing is the most common specification defect there is.

How do you ask what a term means without losing credibility?

Ask a question whose answer contains the definition and which demonstrates you were following, rather than asking for a definition cold. Instead of "what is prior authorisation", ask "when you say it needs prior authorisation, does that mean the treatment cannot be delivered until the payer responds, or that it can proceed at the provider's risk?" You get the definition, you get the exception, and the room hears precision rather than a gap. Two supporting habits: ask early in a relationship rather than in month four, when the same question implies you have been bluffing, and write the answer down so you never ask twice. Asking once is free in almost every organisation. Needing repeated explanation of the same term is what actually costs you, because it tells the room you are not accumulating.

How do you translate engineering constraints back into business language?

By expressing the constraint as a consequence the business can weigh, not as a mechanism. "The replica lags" tells them nothing; "a user who updates their address may see the old one for up to thirty seconds, and the letter run at eleven uses whatever it sees then" gives them a decision to make. The direction of this translation matters as much as the other one, because a business stakeholder who does not understand the cost cannot trade against it, and will experience every engineering objection as obstruction. The specific discipline is to name the affected business event, the size of the window, and who notices — then let them tell you whether it matters, because sometimes the answer is that it genuinely does not and you have been about to spend a month on it.

What are false friends, and why are they worse than unknown words?

A false friend is a term you already know from another domain with a different meaning here, and it is worse than an unknown word because it does not trigger a question. Unknown vocabulary announces itself; a familiar word passes silently into your model with the wrong definition attached, and you build on it for weeks. Settlement, claim, reserve, authorisation, exposure and book all mean different things in payments, insurance and retail, and none of them is ambiguous inside its own industry — they are only ambiguous in a room containing two industries, which is the room a consultant or solution architect is usually in. The defence is a habit rather than a list: when you recognise a term immediately, that is the moment to confirm it, because your confidence is coming from a different business.

Modelling a domain

What is a bounded context, and why is it a linguistic boundary?

A bounded context is the scope within which a term has exactly one meaning, and the boundary is drawn where the language changes rather than where the code or the team happens to split. That framing is the useful one because it gives you a detection method: if servicing and risk both say "customer" and mean different things, they are two contexts whether or not they share a database, and pretending otherwise produces one enormous shared object serving neither. The technical consequences follow from the linguistic fact rather than the reverse — separate models, translation at the seam, and shared identifiers rather than shared schemas. Two contexts sharing identifiers can be reconciled; two contexts sharing a schema become one context with two owners, no coherent model, and a change process where every field addition requires a negotiation.

What is event storming, and what does it produce that a workshop does not?

It is a session where domain experts and engineers put the business's events on a wall in time order, then add the commands that cause them, the actors who issue them, the policies that react, and the points of disagreement. What it produces that a requirements workshop does not is the whole timeline including the parts nobody owns, because ordering events forces the gaps and the handoffs into view — and it surfaces disagreement between experts, which is the highest-value output and the one a document-driven process hides. The mechanism is that it is cheap to be wrong: moving a sticky note costs nothing, so people commit to a position early. The failure mode is running it as a diagramming exercise with engineers only, at which point you have produced your own assumptions in an unfamiliar notation.

Show me an event-storming output as a timeline of domain events.

The output is not a diagram. It is an ordered list of things that happened, with the arguments still attached.

Timeline for one motor claim. Past tense throughout, no system names.

  ClaimNotified            actor: policyholder or broker
                           policy: start the notification clock
  PolicyValidatedAtLoss    <- HOTSPOT. Two experts disagreed: is cover
                              judged at the date of loss or the date of
                              notification? Answer: date of loss. This
                              changes the data model - we need what the
                              policy WAS, not what it is.
  ClaimRegistered          command: RegisterClaim
  ReserveEstimated         actor: adjuster. policy: reserve must exist
                           before any payment. Actuarial reporting reads it.
  DamageInspected          external actor: engineer or garage
  LiabilityDecided         <- HOTSPOT. Can be partial. Nobody had modelled
                              a percentage, only accept or decline.
  PaymentAuthorised        policy: above 10k requires a second approver
  ClaimSettled
  ClaimClosed              <- and here the wall stopped, until someone
                              said "unless it reopens"
  ClaimReopened            actor: policyholder, adjuster, or a court.
                           Can occur YEARS after ClaimClosed. Reverses
                           nothing - it appends.
  RecoveryReceived         from a third party's insurer. Money arrives
                           after settlement, in the opposite direction.

WHAT THE WALL CHANGED
  - ClaimClosed is not terminal. The first draft model had a closed flag.
  - Two events carry money in opposite directions after settlement.
  - Cover is evaluated against historical policy state, so the policy
    model is bitemporal whether we wanted that or not.

The hotspots are the output. Three of them here, each one a disagreement between two people who both do the job, and each one invalidating a modelling decision that had already been made informally. No document would have produced them, because each expert's own account was internally consistent.

The last three events are the ones that decide the model. A design built from the first eight would have a terminal closed state, a single money-out direction and a current-state policy record — and all three would need unpicking in the second year, after data had accumulated against them.

Past tense is not a stylistic rule. Naming events in the past tense forces them to be facts rather than intentions, which is what stops the wall becoming a process diagram of what the software should do. ClaimReopened is a fact about the business; ReopenClaim is a screen somebody wants.

Notice there are no system names anywhere. That is deliberate: the moment the wall says "in Guidewire" the conversation becomes about the current implementation, and the events you are trying to find are the ones the current implementation does not represent.

What is the difference between a business rule and an implementation detail?

A business rule is a statement the business would still make if the software did not exist; an implementation detail is a consequence of how you chose to build it. "A refund cannot exceed the original payment" is a rule and would survive onto paper. "Refunds are processed in a nightly batch" is almost always a detail, unless a regulation or a counterparty's file schedule requires it — in which case it has quietly become a rule. The test is to ask what would have to change for it to stop being true: a rule changes when a regulator, a contract or a commercial decision changes, and a detail changes when you deploy. The reason to separate them is that rules belong in the domain model where they can be read and challenged, while details belong at the edges, and mixing them produces a system where nobody can find the rule.

Where do business rules actually hide?

In stored procedures and triggers, in a spreadsheet somebody maintains, in a report's WHERE clause, in a validation rule on a form nobody owns, in a scheduled job's timing, in the configuration of a vendor package, and in one person's head. The pattern is that rules end up wherever it was cheapest to put them at the moment they were needed, which is rarely the application code. The practical consequence for anyone replacing a system is that reading the application source produces an incomplete rule set, and the missing rules are disproportionately the ones about money and eligibility, because those were the ones the business changed most often and therefore moved somewhere they could change without a release. The person's head is the worst case, and finding it usually means noticing that a step in the process has no system at all.

Show me a business rule extracted from a stored procedure.

Rules found in a procedure arrive as arithmetic with no explanation, and the job is to restate them in domain terms before you decide anything.

-- sp_calc_delivery_fee, last modified 2014, no comments, no tests
IF @order_total < 5000
    SET @fee = 499;
ELSE IF @order_total < 15000 AND @cust_grp NOT IN (3, 7)
    SET @fee = 299;
ELSE
    SET @fee = 0;

IF @postcode LIKE 'IV%' OR @postcode LIKE 'KW%' OR @postcode LIKE 'HS%'
    SET @fee = @fee + 1200;

IF DATEPART(dw, @order_date) = 6 AND DATEPART(hh, @order_date) >= 14
    SET @fee = @fee + 0;  -- ??? left in deliberately, do not remove

Restated in the business's own terms, after asking three people:

RULE 1  Delivery is free above 150 pounds, 2.99 between 50 and 150,
        4.99 below 50. All values in pence in the procedure.
RULE 2  Customer groups 3 and 7 - wholesale and staff - never get the
        mid-tier rate. They pay 4.99 up to the free threshold. This is
        a commercial rule from the wholesale contract, still in force.
RULE 3  Highland and island postcodes carry a 12 pound surcharge,
        because the carrier charges us a zonal rate. This is a
        pass-through of a supplier cost, not a margin decision.
RULE 4  The Friday afternoon branch adds nothing. It was a Saturday
        delivery surcharge, removed in 2016 when the carrier changed.
        The branch was left because someone was unsure. It is dead.

Three of the four are genuine business rules and would survive a rewrite; one is an archaeological artefact. The distinction cannot be made from the code, which is the entire reason this exercise needs a person from the business in it.

Rule 2 is the one that matters and the one a rewrite loses. Customer groups 3 and 7 are meaningless as integers, and an engineer reimplementing this from the procedure would either drop the condition or carry the magic numbers forward. It is a contractual obligation, so dropping it is a breach and carrying it forward opaquely means the next person drops it instead.

Rule 3 has a different character worth naming: it is a pass-through of a supplier's cost, which means it changes when the carrier contract changes rather than when the business decides. Recording that origin is what tells the next engineer who to ask before touching it.

The dead branch is the cheapest lesson here. It survived a decade because nobody could establish why it was there, and the only thing that resolves that is asking someone with institutional memory. Deleting it without asking is how the previous surcharge came back three years later.

What is an anti-corruption layer, and when do you need one?

It is a translation boundary in front of a system whose model you must consume but do not want to inherit, converting its vocabulary into yours at the edge. You need one whenever you integrate with something older, externally owned or modelled around a different business — a vendor core platform, a partner's API, a legacy mainframe interface — which is to say most of the time in a specialist industry. What it buys is that the foreign model's compromises stay in one place with one owner, so a change on their side is a change to your translator rather than a change to every service. The cost is a mapping nobody enjoys maintaining and a real temptation to skip it under deadline. Skipping it is how a vendor's field names end up in your domain events, permanently, and how their upgrade becomes your migration.

Working with domain experts

Show me the questions for a first meeting with a domain expert.

Their time is the scarce resource, so the questions have to be ones no document could answer. Each of these surfaces a specific thing.

45 minutes with an operations lead. What each question is really for.

1  "Walk me through the last one of these you handled, not a typical
    one - the actual last one."
   surfaces  the real path including the workaround, because a specific
             recent case cannot be described from the procedure

2  "Which step do you do outside the system?"
   surfaces  the spreadsheet, the email approval, the phone call to the
             other department. This is where the undocumented rules are.

3  "What goes wrong most often, and roughly how often?"
   surfaces  frequency, which is the number that decides whether we
             automate, tolerate or refuse the exception

4  "What do you do when the two systems disagree?"
   surfaces  which system the business actually treats as authoritative,
             which is often not the one the architecture says

5  "Is there anything the system makes you do that seems pointless?"
   surfaces  either a dead rule we can delete or a constraint whose
             reason has been forgotten. Both are valuable.

6  "Who else would answer any of this differently?"
   surfaces  the second expert, and the disagreement between them

7  "What would you fix if you could fix one thing?"
   surfaces  their priorities, and buys the relationship. Ask it last
             and write the answer down where they can see you write it.

WHAT NOT TO ASK
  - anything answered by a document you have not read yet
  - "what are the requirements", which asks them to do your job
  - a definition cold. Ask a question whose answer contains it.

The first question does most of the work. Asking for the typical case gets you the procedure, recited; asking for the last actual case gets you the exception, because there is almost always something non-standard about any specific instance and they will mention it without realising it is interesting.

Question four is the one engineers never think to ask and the one that most often overturns a design. The architecture names a system of record; the business has a practice about which screen to believe, and the practice is what the numbers in the monthly report are based on.

Question five is doing two jobs. Sometimes it finds a dead rule, which is a quick win you can deliver in week two and which buys enormous goodwill. Sometimes it finds a constraint whose reason has been forgotten, which is the most dangerous thing in the domain because the next person to arrive will delete it.

Question seven is not filler. An expert who has been interviewed by three consultants and seen nothing change will give you the procedure and keep the rest. Asking what they would fix, visibly recording it, and coming back with progress on something small is what converts a source into a collaborator.

How do you work with an expert who has been burnt by IT before?

Assume the scepticism is earned and evidence-based rather than a personality trait. Someone who has been interviewed by three project teams, watched two systems get cancelled and had their objections overruled once is behaving rationally by giving you the sanitised version. What changes it is delivering something small and visible early — fixing the report that has been wrong for two years, removing the field they have been typing "N/A" into since 2021 — because that demonstrates the loop closes. Beyond that: bring your understanding back for correction rather than asking them to explain it again, credit them by name when their knowledge shapes a decision, and never let them discover a change to their process from a release note. The thing to avoid is arguing that this time is different, which is exactly what the last three teams said.

Why do you keep asking why until you reach the constraint?

Because the first answer is almost always a description of the current process rather than a reason, and you cannot design against a description. "The file goes out at four" becomes "because the bank stops accepting it at five" becomes "because their settlement window closes and a late file waits until tomorrow" — and only the third answer tells you what is actually fixed, what happens if you miss it, and where the flexibility is. Stopping too early produces a design that faithfully reproduces an accident. There is a stopping rule: you have reached the constraint when the reason lies outside the organisation's control, or names a regulation, a contract, a counterparty or a physical fact. If the reason is still "that is how we do it" you have found a habit, and habits are negotiable.

Show me a constraint traced back to its origin.

The same question asked five times, and the point is that two of these four chains end in something you can change.

CHAIN A  "Payments must be raised by 3pm."
  why?  the file must reach the bank by 4pm
  why?  their cut-off for same-day settlement is 4:30pm
  why?  the clearing scheme's window closes then
  why?  scheme rule, published, applies to every participant
  ORIGIN  external scheme rule. IMMOVABLE. Design around it: the 3pm
          internal deadline is an hour of self-imposed buffer, and THAT
          part is negotiable if we can make the run faster.

CHAIN B  "Two people must approve any refund over 500 pounds."
  why?  it is in the finance control framework
  why?  the external auditor raised it as a finding in 2019
  why?  a single employee issued 40k of refunds to their own account
  ORIGIN  a real fraud plus an audit finding. IMMOVABLE in substance,
          but the 500 threshold is ours - it was chosen as "about a
          day's takings" in 2019 and has never been revisited.

CHAIN C  "Customers must be re-verified every two years."
  why?  the KYC policy says so
  why?  it was written when the rules required periodic review
  why?  the rules changed in 2023 to risk-based review
  why?  nobody updated the policy
  ORIGIN  a regulation that no longer says this. HABIT WEARING A
          REGULATION'S CLOTHES. Needs compliance sign-off, not a
          rewrite, and it removes work for 90% of customers.

CHAIN D  "The address form asks for the postcode twice."
  why?  the second one feeds the credit check
  why?  the credit bureau's field was mapped separately in 2011
  why?  nobody joined them up
  ORIGIN  an integration accident. DELETE IT.

Four superficially identical constraints, and the interesting result is that only one is genuinely immovable. Every one of them would have been reported by a stakeholder as "we have to do this", in the same tone.

Chain A shows the most common shape: a real external constraint with a self-imposed buffer wrapped around it. The scheme rule is fixed and the 3pm deadline is not, so the negotiable hour is invisible until you separate them — and it is usually where the improvement is.

Chain B is the one to handle carefully. The control is not negotiable, because it exists for a documented reason and an auditor is watching, but the parameter is ours and was set arbitrarily seven years ago. Distinguishing a control from its threshold is a senior move: it lets you improve the process without touching the thing that would be a finding.

Chain C is the case worth naming unprompted in an interview. A rule that cites a regulation is treated as untouchable, and regulations change more often than internal policies do — so a periodic re-read of the actual rule, by someone who will follow the chain, finds work the organisation no longer has to do.

The test that separates the four is whether the final answer names something outside the organisation's control. A, B and C all reach outside; only C's outside reference turns out to be stale. D never leaves the building, which is the signature of a habit.

How do you tell a genuine constraint from an inherited habit?

Follow the why-chain to its end and see whether it leaves the organisation. A genuine constraint terminates in a regulation, a contract, a counterparty's behaviour, a physical fact or a scheme rule — something the business could not change unilaterally even if it wanted to. A habit terminates in "that is how we have always done it", in a person's preference, or in a system that no longer exists. Two refinements matter. First, check the currency of the external reference, because a rule citing a regulation may be citing a version that changed. Second, separate the control from its parameters: the requirement for dual approval may be immovable while the threshold, the timing and the mechanism are entirely yours. Most improvement lives in that second category, and most failed change attempts went after the first.

Show me the spreadsheet that runs the company.

There is always one, it is never in the architecture diagram, and finding it is one of the highest-value things a new engineer can do.

Found in week 3, on a shared drive. Owner: one analyst in Finance.

WHAT IT IS
  pricing_matrix_v14_FINAL_use_this_one.xlsx
  47 tabs. 2,100 rows of customer-specific pricing overrides.
  Updated by hand, roughly weekly, by one person since 2018.

WHAT DEPENDS ON IT
  - a nightly job imports two tabs into the quoting system
  - the sales team quotes directly from a printed extract
  - the monthly revenue report is built from it, not from the ledger
  - three of the overrides are contractual and legally binding

WHY IT EXISTS - and this is the part that matters
  Pricing overrides need to change within a day of a negotiation.
  Changing them in the system requires a release. Releases are
  fortnightly. The spreadsheet is not a workaround for a missing
  feature; it is a workaround for a deployment cadence.

WHAT IS ACTUALLY WRONG WITH IT
  no history, so nobody can say what price applied in March
  no validation, and two rows currently contradict each other
  no access control, and it is legally binding
  one person, no successor, and she is retiring in eighteen months

WHAT NOT TO DO
  Replace it with a screen. That was tried in 2021. The screen needed
  a release to add a new override type, so within a month people were
  using the spreadsheet again and pasting into the screen.

The diagnosis in the third block is the whole answer. The spreadsheet is not evidence of an undisciplined business; it is a rational response to a system that cannot change at the speed the business changes. Any replacement that does not match that speed loses, and it will lose quietly, by being bypassed.

The dependency list is why this is urgent rather than untidy. A legally binding term with no access control and no history is a real exposure, and the revenue report being built from it rather than from the ledger means the business's reported numbers have a manual step in them that no control covers.

The retirement date is the deadline nobody has written down. Institutional knowledge concentrated in one person is the same bus-factor problem as a system only one engineer understands, and it is treated less seriously because it does not appear on any technical risk register.

The failed 2021 attempt is the part to bring up unprompted. It shows why the correct move is to make the override rules data rather than code — editable without a release, versioned, validated, permissioned — which gives the business the speed the spreadsheet gave them and takes back the control it cost.

What do you do when two experts contradict each other?

Treat it as the most valuable finding of the week rather than as noise, and resolve it explicitly rather than averaging it. First establish whether they are describing different things: very often both are right within their own scope, and the contradiction is a bounded-context boundary announcing itself. If it is a genuine disagreement about one fact, get them in the same conversation with the specific case in front of them, because the abstract version is arguable and a real transaction is not. Then have someone decide and write down who decided, when and on what basis — an unresolved contradiction does not stay unresolved, it gets resolved silently by whichever engineer implements it first. The failure mode to avoid is picking the more senior or more available expert, which produces a model the other one will not accept and will work around.

Regulated and high-consequence contexts

What changes when a mistake has regulatory or safety consequences?

The cost of being wrong stops being proportional to the size of the error, and the reviewer stops being you. Practically, four things change. Evidence becomes a product requirement: it is not enough to behave correctly, you must be able to demonstrate afterwards that you did, to someone hostile, years later. Deletion and mutation become restricted, which changes the data model rather than the policy document. Change control becomes slower and deliberately so, because an unreviewed release is itself a finding. And the definition of done moves outside engineering, since the rule is satisfied when a compliance function accepts it. The habit that follows is to translate every obligation into a technical constraint before design starts and write the translation down, because obligations in legal language and constraints in architectural language are not interchangeable and the translation is where errors live.

Why are audit trails non-negotiable?

Because in a regulated domain the record of what happened is a deliverable in its own right, not a debugging aid. An audit trail answers a question asked by someone outside the company, about a specific transaction, potentially years later, and the answer has to be defensible: who did what, when, on whose authority, and what the state was before and after. That is a stronger requirement than logging in three ways — it must be immutable, it must be complete rather than sampled, and it must be retained past the point where the operational data would have been deleted. The design consequence people miss is that it constrains the rest of the system: an in-place update destroys the before-state, so an auditable entity is append-only whether or not you wanted event sourcing.

Show me an audit-trail requirement expressed concretely.

"We need an audit trail" is not a requirement. This is what it has to become before anyone can build or test it.

Auditable entity: payment instruction

WHAT IS RECORDED - one immutable row per state transition
  event id            uuid, unique, generated at write time
  entity              payment_instruction id and version
  what changed        field, before value, after value. Before value is
                      mandatory. A null before value is a defect, not
                      an empty case.
  actor               authenticated user id AND the role in effect at
                      that moment, because roles change
  on whose authority  the approval reference, where the action needed one
  source              channel and client ip, or the batch job id and the
                      file it was reading
  when                event time from the application, in UTC, plus the
                      local timezone it was performed in
  why                 reason code from a controlled list, free text only
                      in addition to it, never instead

IMMUTABLE HOW
  - append-only table, no UPDATE or DELETE grant to the application role
  - write is in the same transaction as the change it describes, so a
    change without its audit row is impossible rather than unlikely
  - hash chain over the previous row, verified by a nightly job that
    alerts on a break
  - backups of this table are restore-tested quarterly

RETAINED HOW LONG
  7 years after the instruction's final state, not 7 years after
  creation. So the clock starts at closure, and the row cannot be
  deleted while the parent could still be reopened.

WHAT THIS BLOCKS
  - a subject-access deletion request does not remove these rows. It
    pseudonymises the actor for staff, and the legal basis for
    retention is recorded against the exemption.
  - no in-place UPDATE on payment_instruction anywhere in the codebase.
    This is enforced by grants, not by review.

Every line here exists because a vaguer version failed an audit somewhere. The one to notice first is the mandatory before-value: without it the trail tells you a change occurred and not what the state was, which answers none of the questions an auditor asks.

The role-in-effect field is the detail candidates never mention. Recording the user identifier alone means that when someone's permissions change, the trail can no longer establish whether they were entitled to act at the time — and that is precisely the question asked when something has gone wrong.

The immutability section is where "non-negotiable" becomes engineering. Immutable by convention means mutable, so the guarantee has to rest on grants the application does not hold and on a hash chain that makes tampering detectable. Writing the audit row in the same transaction is what turns a completeness requirement into an invariant.

The retention clock is the subtle one. Starting it at creation is the intuitive implementation and it is wrong for anything that can reopen, because the parent outlives its own retention period. That single mistake is a common finding.

The last block is the honest part: this requirement removes options elsewhere, including the right-to-erasure path, and those conflicts are resolved by legal basis rather than by engineering preference.

What is segregation of duties, and why is it a domain requirement?

It is the rule that no single person may control every step of a sensitive process — typically that the person who initiates a transaction cannot approve it, and neither can release it. It is a domain requirement rather than a security feature because it comes from the business's control framework, usually via an auditor or a regulation, and it is specified in terms of business roles and transaction types rather than system permissions. That distinction matters in design: implementing it as two permissions on one role model misses the point, because the requirement is about the identity of the acting humans across several steps, including the case where one person holds both roles legitimately and must still not use both on the same transaction. It also has to survive delegation, holiday cover and emergency access, and those exceptions are where real implementations fail.

Show me segregation of duties as an approval flow.

The requirement is about who may act at each step, so the flow has to name the exclusions rather than just the sequence.

flowchart TD
    A[Operator raises a payment run<br/>and is barred from approving it] --> B{Total above the<br/>delegated limit}
    B -->|no| C[Approver from a different team<br/>reviews and releases]
    B -->|yes| D[Second approver required<br/>from finance control]
    D --> C
    C --> E[File submitted by a service account<br/>no human can log in as]
    E --> F[Audit record written for raiser,<br/>approvers, amount and release time]

The first box carries the actual requirement, and it is a negative one. Most implementations encode the sequence — raise, approve, release — and enforce the exclusion nowhere, so a user who holds both roles can walk their own payment through and every step will look correct in the log.

The threshold branch is where the control framework and the system meet. The existence of a second approver above a limit is usually an audit finding made concrete, and the limit itself is an internal parameter — which means it should be configurable data with its own change record, not a constant in code.

The service account box is the part engineers get wrong most often. If a human can authenticate as the account that submits the file, the segregation is theatre, because that human can submit a file that no approver saw. The same argument applies to anyone with write access to the file's directory or to the database behind it, which is why this control drags production access into scope.

The exceptions are what break real implementations and what an interviewer will probe. Holiday cover means someone temporarily holds both roles; emergency access means someone bypasses the flow at three in the morning. Both are legitimate and both must be time-bounded, separately approved and separately reported, because an emergency path with no report is the control's largest hole.

What is a four-eyes check, and where does it belong?

It is the requirement that a second competent person reviews an action before it takes effect, and it belongs in the domain model rather than in the user interface. Putting it in the interface means it is bypassed by every other entry point — an API, a batch import, a support tool, a database fix — which is exactly where the risky changes happen. Modelled properly, the pending action is a first-class entity with its own state, its own audit trail and its own expiry, and the effect is applied only when a second identity that is not the first has approved it. Two details separate a real implementation from a nominal one: the reviewer must have enough information to review rather than a diff of primary keys, and rubber-stamping must be detectable, because a check where the same pair always approve each other in eleven seconds is not a control.

Why must regulation be a design input rather than a review gate?

Because the obligations constrain structure rather than behaviour, and structure is the expensive thing to change late. A residency rule fixes deployment topology before you choose a region, and it applies to backups, logs and the screens support staff can see, not only to the primary database. A retention obligation decides whether hard deletion is available to you at all, which changes the data model. An authentication requirement can put an interactive challenge inside a flow you would otherwise have made asynchronous. Treat any of these as a month-nine review and the finding is not a defect but an architecture that cannot be made compliant, only replaced. The discipline is to write each obligation's technical translation down at design time so it can be challenged by someone who knows the rule, since the translation is where the misreadings are.

Legacy and the reasons behind it

Why are legacy systems usually load-bearing?

Because they have absorbed twenty years of exceptions that nobody wrote down, and the exceptions are the business. A system that has been in production for two decades has been corrected every time it produced a wrong answer, so its accumulated peculiarities are a compressed record of every edge case the business has actually encountered — including the ones that occur once a year and the ones that exist because a single large customer negotiated something in 2007. That knowledge exists nowhere else: not in the documentation, which describes the original design, and not in the current staff, who inherited the behaviour rather than deciding it. The practical consequence is that the old system's oddities are your requirements specification, badly written, and the only way to get them out is to treat each one as a question rather than as a defect.

Show me legacy behaviour that looks like a bug and is a requirement.

Every replacement project has a list like this, and the difference between a successful one and a failed one is whether the list was made before the cutover.

Four behaviours flagged as defects by a rewrite team in week 2.

1  "Invoices dated the 29th, 30th or 31st are re-dated to the 28th."
   Looks like  a lazy month-end bug
   Actually    the customer's ERP rejects invoice dates that do not
               exist in every month of their fiscal calendar. Agreed
               in the 2013 contract. Two customers, 40% of revenue.
   Verdict     REQUIREMENT. Needs to be per-customer configuration,
               not a global rule as it is today.

2  "Cancelled orders still appear in the daily volume report."
   Looks like  a missing WHERE clause
   Actually    the report feeds a carrier capacity commitment. The
               carrier is booked on gross volume and charges for the
               slot whether we use it or not.
   Verdict     REQUIREMENT, but the report should say gross, and a
               separate net figure should exist. The name is the bug.

3  "Postcode validation accepts a blank for one country only."
   Looks like  an unfinished validation
   Actually    that country has addresses without postcodes. The blank
               is correct and rejecting it lost sales for a fortnight
               in 2019 when someone tightened it.
   Verdict     REQUIREMENT. Add a comment and a test named after the
               incident, so the next person does not repeat it.

4  "Prices are recalculated at 02:00 even when nothing changed."
   Looks like  a wasteful job
   Actually    nothing. The upstream feed it was reacting to was
               decommissioned in 2020. It has been recalculating
               identical values for six years.
   Verdict     DEFECT. Delete. Confirmed with the pricing owner in
               writing, because this is the one that cannot be undone
               cheaply if we are wrong.

Three of four are requirements, which is roughly the ratio to expect and the reason "we will clean this up in the rewrite" is such a reliable predictor of a failed rewrite. Each one was reported in good faith by a competent engineer reading the code.

Item two is the most instructive. The behaviour is correct and the name is wrong, so the fix is a rename plus an additional figure rather than a change in logic. That pattern — right behaviour, misleading label — accounts for a large share of apparent legacy defects, and changing the logic to match the label is how a rewrite breaks a commercial commitment.

Item three shows the cost of getting this wrong in the other direction. Somebody already tightened that validation, already lost a fortnight of sales, and the knowledge was retained only in the code. A test named after the incident is the cheapest possible way to stop the loop.

Item four is a genuine defect and note how it was resolved: in writing, with the business owner named. The asymmetry is the reason — leaving a wasteful job costs compute, deleting a load-bearing one costs a quarter, so the confirmation is worth the two days it takes.

Why is "the system does that because of a regulation in 2009" a real answer?

Because it names an origin outside the organisation, which is the only kind of answer that lets you decide anything. It tells you who to ask, what to read, and what would have to change for the behaviour to stop being required — which is more than "that is how it has always worked" ever gives you. It is not, however, a reason to stop: the follow-up is whether the regulation still says that, since rules change more often than internal implementations of them do, and a behaviour justified by a superseded rule is a habit wearing a regulation's clothes. So the answer is genuinely useful and genuinely incomplete. Treat it as a citation to be checked rather than as a closing argument, and record what you find, because the next engineer will otherwise ask the same question and get the same 2009 answer.

What is the risk of a rewrite in a domain you do not understand?

That you faithfully reproduce the visible behaviour and silently drop the exceptions, which are the part the business actually depends on. The failure pattern is consistent: the new system handles the happy path better, passes every test written from the specification, and then produces wrong answers for the two per cent of cases nobody knew existed — discovered in production, by customers, at the worst possible moment. Because the exceptions are disproportionately about money, eligibility and specific large customers, the two per cent is not evenly distributed in value. The mitigations are to run both systems in parallel and reconcile the outputs before switching, to treat every apparent legacy defect as a question with a named business owner, and to sequence the migration so the first thing you move is something small enough that being wrong is survivable.

How do you decide what to keep when replacing a legacy system?

By classifying every behaviour rather than every module, and by making somebody in the business accountable for each classification. The categories are requirement, requirement with a wrong name, dead, and unknown — and the honest handling of unknown is to keep the behaviour and mark it, not to guess. The mechanism that makes this tractable is parallel running with reconciliation: send the same inputs to both systems and compare outputs, because every difference is either a bug in the new one or an undocumented rule in the old one, and either way you have found something you could not have found by reading. The judgement to state in an interview is that behaviour you cannot explain is kept by default in a regulated domain and dropped by default in a low-consequence one, because the asymmetry of cost is different.

Show me a domain decision record written for the next engineer.

The rule is worth less than the reason, because the next engineer can read the rule from the code and cannot recover the reason at all.

DDR-017  Cover is evaluated against the policy as it stood at the
         date of loss, not the date of notification

Status    Accepted, 14 May 2026. Supersedes nothing.
Decided   Motor claims domain. Affects claims, policy, and the
          actuarial reserving extract.

THE QUESTION
  When a claim is notified, which version of the policy determines
  whether the loss is covered?

WHAT WE DO
  The policy version in force on the date of loss. If the policy was
  endorsed after the loss but before notification, the endorsement is
  ignored for this claim.

WHY - and this is the part that must survive
  1  Insurance contract law: cover is a promise about the state of
     the contract at the moment of the insured event.
  2  Confirmed with the head of claims and with legal, 9 May 2026,
     against two real 2024 cases where the answer mattered.
  3  The opposite reading would let a policyholder increase cover
     after a loss and claim the higher limit.

WHO SAID SO
  R. Iyer, Head of Claims. E. Novak, Legal. Both consulted directly;
  the claims procedure document is silent on it and the previous
  system implemented it correctly but by accident.

WHAT THIS FORCES ON THE DESIGN
  The policy model must be bitemporal: we need what the policy WAS on
  a past date, and separately what we BELIEVED it was on a past date,
  because a backdated correction to a policy record is legitimate and
  must not silently change the outcome of a settled claim.
  So: no in-place amendment of policy versions, ever.

WHEN THIS WOULD STOP APPLYING
  If the product were changed to an occurrence-agnostic form, or if
  a regulator mandated notification-date evaluation. Neither is
  expected. Re-check if the product line changes jurisdiction.

WHAT WE ALMOST DID
  Used the current policy version, because that is what the API
  returns by default and every existing query does it. This would
  have been wrong in roughly 1 claim in 300 and undetectable in
  testing.

The section that justifies the whole document is "when this would stop applying". A rule with no stated boundary is indistinguishable from an accident to the next person, so they either preserve it superstitiously or delete it confidently, and both are failures.

Naming the people and the date is what makes it auditable rather than anecdotal. Two years from now the question will be asked again, and the record either points at a named authority and a dated conversation or it points at an anonymous claim that somebody agreed.

The design-consequence block is why this belongs with the engineering artefacts rather than in a business wiki. One domain answer forced bitemporality and forbade in-place amendment, and an engineer who finds the immutability rule without this record will reasonably assume it is over-engineering.

"What we almost did" is the most valuable paragraph and the one nobody writes. The wrong answer is always the convenient one, so the next engineer under deadline pressure will be drawn to exactly the same shortcut, and naming it with its error rate is what stops them.

Why is recording the reason more valuable than recording the rule?

Because the rule is already in the code and the reason exists nowhere. An engineer reading the codebase can determine what the system does with reasonable effort; no amount of reading recovers why, and without why they cannot tell a constraint from an accident. That distinction is what governs every subsequent change: a rule whose reason is known can be safely modified when the reason changes and safely defended when someone proposes removing it, while a rule with no recorded reason is either preserved superstitiously forever or deleted by somebody confident. Both failures are common and both are expensive. The minimum useful record is the decision, the origin of the constraint, who confirmed it and when, what it forces on the design, and what would make it stop applying — and the last of those is the field most often missing.

Interview traps

What do you say when you have no experience in the interviewer's industry?

Say so plainly, then demonstrate the acquisition method on their domain in the room. The claim that lands is not that you know their business but that you know the shape of the questions: who are the parties, what can each one refuse, where does money move against the direction of goods, which clock is binding, what happens when it is reversed. Then use them — ask what happens on their exception path and what their equivalent of reconciliation is. Cite a domain you did learn and how long it took, honestly, including what you got wrong. What fails is either bluffing, which their next question exposes, or apologising, which invites them to treat the gap as disqualifying rather than as a fortnight of reading. A demonstrated method is more persuasive than borrowed vocabulary.

Why is "I pick up domains quickly" a weak answer?

Because it is an unfalsifiable claim about yourself where a description of a method would be evidence. Every candidate says it, none can be checked, and the interviewer's next question is invariably "how", at which point the answer is either a specific process or an embarrassed generality. The strong version names the mechanics: I start with a primary document rather than internal wikis, I read the schema before the design docs because the schema cannot lie about what has been needed, I trace one real transaction end to end, I shadow an operator and ask about frequency rather than possibility, and I test myself by predicting what they will say. Then attach a timeline and an outcome from a real case. The underlying point is that speed is a claim and method is a demonstration.

What is being tested by "walk me through what happens after a customer places an order"?

Whether you think in transactions and parties rather than in services, and how far past the happy path you get unprompted. A weak answer describes the systems — the order service calls the payment service — which is an architecture answer to a domain question. A strong one names the parties and their obligations, the points where money and goods move in different directions, the clocks that start, the states that are not terminal, and the party who can refuse. It also reaches the unglamorous end: allocation, partial shipment, the reconciliation that proves the payment matched the order, the return that arrives six weeks later. The tell interviewers listen for is whether you volunteer the exception path, because the happy path is on a slide somewhere and everything expensive is in the rest.

Why does naming the exception path score more than describing the happy path?

Because the happy path is already automated, already documented and already understood by everyone in the room, so describing it demonstrates nothing. The value in every domain sits in reversals, disputes, partial fulfilment, reopened cases and the customers whose contract overrides the standard rule — and none of it is written down, because the people who handle it never had to write it down. This is structural rather than a documentation failure: standard behaviour gets automated and therefore recorded in code, while exceptional behaviour stays with the people who handle it, which is precisely why the operations team has headcount. An interviewer asking a domain question is checking whether you know where the difficulty lives, and volunteering the exception is the cheapest signal that you have worked in a real business.

What does an interviewer conclude when every domain answer is a definition?

That you have read about the domain rather than worked in it, and the conclusion arrives faster than candidates expect. Definitions are now free — anyone can be told what a chargeback is in ten seconds — so reciting one answers a question nobody asked and consumes the time you had to show judgement. What distinguishes experience is the second-order material: how often the case occurs, what the business does when it does, which of the plausible readings this kind of organisation actually operates, and what it costs when someone gets it wrong. So the shape of a strong answer is a short definition followed immediately by a consequence or an exception. If you only have the definition, the honest move is to say so and ask which reading applies here, which reads as precision rather than as a gap.

How do you avoid over-claiming domain expertise you do not have?

By stating the boundary yourself, in the same sentence as the claim, because the interviewer will find it anyway and the only variable is who found it first. "I owned the dispute lifecycle and can talk about scheme deadlines and evidence handling; I never worked on settlement and would need to read" is a stronger answer than a broad claim, and it makes everything else you say more credible. The specific over-claims to avoid are equating tenure with knowledge, describing a system you integrated with as one you understand, and using a term you have only read. One over-claim caught in an interview retroactively discounts every other claim you made, which is a much larger loss than admitting a gap — and admitting a gap costs almost nothing when it comes with a method for closing it.

What is an interviewer testing when they ask what you learned about the business at your last job?

Whether you were curious about the business or merely employed by it, which is the cleanest available proxy for how you will behave in their domain. A strong answer names a specific non-obvious thing — a constraint, an exception, a reason behind an inconvenient rule — explains why the business works that way, and then connects it to an engineering decision you made differently as a result. It usually has a number in it, because frequency and money are the things people who were paying attention picked up: this happens twice a week, this customer is forty per cent of revenue, this deadline is a scheme rule and missing it loses the dispute regardless of merit. It is comfortable naming what the candidate still did not understand when they left. A weak answer describes the product rather than the business, or recites what the company does from its own website, or retreats into the technology stack — which tells the interviewer that four years of exposure produced familiarity with one codebase and no model of the business it served. The underlying test is whether you ask why unprompted, because nobody in their organisation is going to instruct you to start.