System Design: Strongly Consistent Ledger + External Service Integration
Design two loosely related components for a production-grade environment, and be explicit about the trade-offs behind each decision.
-
Part A — A financial ledger
that is strongly consistent and horizontally scalable.
-
Part B — An integration of an external "Bikemap" routing service
behind a stable internal API.
Assumptions
-
Money movement favors correctness over availability.
Writes must be strongly consistent; reads may be tuned for performance as long as correctness is preserved.
-
Bikemap is a third-party routing API
used to fetch bicycle routes and metadata. Treat it as a network dependency with SLAs, rate limits, and versioned contracts.
Constraints & Assumptions
These numbers are anchors to scope the discussion, not hard requirements — state your own and design to them.
-
Ledger:
target a high sustained write rate (e.g. on the order of thousands of postings per second, with hot accounts touched by most transfers), balances read far more often than written, and an audit/retention horizon measured in years.
-
Consistency boundary:
strong, serializable consistency on the
write
path; bounded staleness is acceptable for non-authoritative balance/statement
reads
.
-
Bikemap:
a contracted third-party with a finite request quota, a versioned schema, a published per-call latency budget, and occasional throttling/outages — design assuming all of these can and will be exercised.
-
Money:
single currency per account; cross-currency is modeled explicitly, never by summing across currencies.
Part A — Strongly Consistent, Scalable Ledger
Design a ledger that satisfies the following requirements.
1. Consistency & correctness
-
Double-entry accounting
— every transaction balances to zero.
-
Immutability & auditability
— no destructive updates; corrections are reversible (new reversing entries, not in-place edits).
-
Idempotent writes
with exactly-once
effects
over an at-least-once network.
-
Strong write consistency
— linearizable writes and serializable transactions.
2. Scalability & performance
-
High write throughput with horizontal scaling.
-
Efficient balance reads, including
point-in-time / as-of-time
queries.
3. Reliability & security
-
Multi-AZ durability, backups, and disaster recovery.
-
Encryption at rest and in transit; access controls.
4. Interfaces & operations
-
Well-defined APIs: create account, transfer, hold/release, reverse, query balance, and list transactions.
-
Observability, schema evolution, and operational playbooks.
What to cover
Walk through the data model, the write and read paths, your sharding strategy, how you handle multi-account (and cross-shard) transactions, your audit guarantees, idempotency, and failure handling.
Part B — Integrate the External Bikemap Service
Explain how you would integrate an external Bikemap library/service into a larger application, covering the following.
1. API design
-
An internal domain API that stays
stable even if the provider changes
.
-
Versioning, contracts, and auth/secrets management.
2. Data flow
-
Request flow, caching, rate limiting, retries, timeouts, and circuit breakers.
-
Synchronous vs. asynchronous
flows and background jobs.
3. Error handling & resilience
-
An error taxonomy, fallback strategies, and observability.
4. Deployment considerations
-
Environment promotion (dev / staging / prod), canaries, feature flags, infrastructure, and testing strategy.
Clarifying Questions to Ask
Use these to scope the problem before designing:
-
Scale & shape of load:
expected peak posting rate, read:write ratio, number of accounts, and how concentrated traffic is on "hot" accounts (e.g. a platform fee account touched by every transfer)?
-
Consistency vs. latency:
must balance
reads
be linearizable, or is bounded staleness acceptable for non-authoritative reads? What is the write-latency budget?
-
Money semantics:
single- or multi-currency? Are holds/auth-capture, overdrafts, and reversals in scope? What's the audit/retention horizon?
-
Cross-account scope:
do transfers commonly span accounts that could land on different shards, or can related accounts be co-located?
-
Bikemap contract:
what is the provider's rate limit, latency SLA, and versioning policy? Is a secondary provider available for fallback? Are calls predominantly real-time or batch?
-
Operational bar:
required durability/DR posture (multi-AZ, multi-region?), and who consumes the audit trail (regulators, internal finance)?
What a Strong Answer Covers
The interviewer is listening for these dimensions (not these answers):
-
Invariants stated up front
— the correctness properties that constrain the design, named before any schema.
-
A defensible data model
— entities for accounts, transactions/postings, balances, holds; and a clear, justified stance on which data is authoritative and which is derived.
-
Separated read and write paths
— how writes stay strongly consistent and how reads (including as-of-time) stay fast.
-
Concurrency & idempotency reasoning
— isolation choice, deduplication, and exactly-once
effect
on retry.
-
A sharding strategy and the cross-shard story
— keeping the common case cheap and handling the distributed minority correctly.
-
Audit & integrity guarantees
— immutability, how historical records are protected from undetected change, and how drift is detected.
-
Failure handling and operations
— what happens on crash/partition, plus concrete runbooks and observability.
-
For Part B:
clean isolation of the third party, an explicit error taxonomy with
safe
fallbacks, fleet-wide rate/quota control, and a flag-gated, canaried deploy story.
-
Trade-offs made explicit
— every major decision paired with what it costs.
Follow-up Questions
Be ready for deeper probes:
-
A platform fee account is touched by nearly every transfer and its balance row becomes a contention hot spot — how do you remove that bottleneck without losing the zero-sum guarantee?
-
Your cached balance disagrees with
SUM
of the postings in production. What is your first move, and how do you decide whether the bug is in the cache or in the postings themselves?
-
A cross-shard transfer is left
prepared but uncommitted
after a coordinator crash. How do you resolve the in-doubt transaction, and what is the cardinal rule for all participants?
-
How does the design change at 100× write volume, and what breaks first?
-
Bikemap silently changes a field in its response schema. How does your integration catch this before it corrupts downstream data, and what does the caller see?