Keep the hot path honest
A trading core has one job it cannot get wrong: take an order, match it, fill it, and never lie about the result. Everything else the platform does — risk, reporting, surveillance, the CRM — is real work, but it is not that job. The first architectural decision that matters is drawing the line between the two.
The hot path is small on purpose
On the execution path I let in only the work that the client is waiting for: validate the order, match it, record the fill, update the position. That is the whole list. A fill flows straight to position management so a trader’s exposure is correct the instant the order completes, not on the next poll. Nothing on this path may block on a system the trader is not waiting for.
The discipline is subtractive. Every time someone wants to “just add one more check” to execution, the right question is whether the client is waiting on that check. Usually they are not, and the check belongs somewhere else.
Everything else leaves as an event
The work that does not block the fill leaves the hot path as an event on Kafka. Execution publishes and moves on; risk, reporting, and the rest consume at their own pace. This is what keeps inter-service latency under 100ms even when load spikes with the market rather than the deploy schedule: a slow risk evaluation cannot slow an order, because it was never in the order’s way.
Decoupling is not free. You trade a synchronous guarantee for an eventual one, and you take on the work of making consumers idempotent and the bus durable. For a trading core that holds 100K+ concurrent users, that trade is the right one — the alternative is letting the slowest downstream consumer set the speed of execution.
The audit trail is the source of truth
Every order state transition is recorded. In a regulated venue this is non-negotiable, but it earns its place for a plainer reason: it is the thing that lets operations trust the numbers. When two systems disagree about a position, the log of transitions is the tiebreaker. Build it first, not last, and never let a state change happen that the trail does not see.
What this looks like in practice
Hot reads — sessions, frequently-touched state — live in Redis, kept off the primary database so it stays free for the durable, transactional work only it can do. The bus carries the rest. The result is a core that handles peak load with headroom and a downstream that can be slow, restarted, or replaced without the client ever noticing.
None of this is exotic. It is the same principle applied at every layer: decide what the caller is actually waiting for, and refuse to make them wait for anything else.