Thirty-One Services and Three Versions of Truth
Haven Health, a health insurer, replaced its claims monolith with 31 microservices in 14 months. A single claim submission now spans six services coordinated by a saga with four compensating actions. Duplicate payments rose from 0.3% to 2.1%, and month-end reconciliation takes five days instead of one. Each service was built by the team that owned the old module, so member 'active status' is mastered in three places under different rules; the disputes team has found claims adjudicated against stale status. Regulators require a defensible, reconstructable record of who changed which claim field, when, and under which rule version. Twenty-two services depend on a shared 'common-domain' library; changing a date format in it required a coordinated 22-service release. Product owners write UI-focused user stories, while non-functional requirements live in a 200-page document last updated two years ago. The regulator has asked Haven to demonstrate that claims are processed consistently.
1. Is splitting claims into 31 services a design failure? What evidence would settle the question?
Read the worked answer
The service count is not the diagnosis; the boundaries are. Evidence to gather:
- Coupling. For a single business-rule change on the claims path, how many services must be deployed together? If the answer exceeds one for a pure rule change, the boundary is in the wrong place.
- Data ownership. Three masters of 'active status' is a defect regardless of service count. It means no service owns the concept; each owns a copy with its own rules. That alone explains stale-status adjudication.
- Change amplification. Twenty-two dependents on a shared library, requiring a coordinated release, is the signature of a distributed monolith seam, not a platform.
- Incident attribution. Ask whether duplicate payments track the saga's compensating actions. Non-idempotent submission plus compensations without day-level reconciliation produces exactly this pattern.
Likely finding: the decomposition followed the old module structure and the team topology (one team per service), reproducing the monolith's coupling over a network. That is an organisational boundary problem expressed as an architecture problem. The remedy is neither 'fewer services' nor 'go back to the monolith'. It is to identify the true claim aggregate, place transaction boundaries where strong consistency is genuinely required, and accept that some paths belong in one service with one database.
2. How should non-functional requirements and auditability be expressed so they are testable rather than archival?
Read the worked answer
Today the NFRs live in a document no code path references. Make them executable.
- Write scenarios, not adjectives. For each quality attribute that matters in claims (consistency, auditability, recoverability, month-end throughput, retention), use source, stimulus, response, measure. Example: 'Any field change to a claim is recorded with actor, timestamp, before/after value and rule version, and is retrievable within five seconds for seven years.'
- Make each one an acceptance criterion and a pipeline test. Auditability becomes a contract test asserting that every write path emits an audit event, plus a schema for that event. Throughput becomes a load test at month-end peak shape.
- Put the NFRs in the definition of done for every story touching claim state. A story without its audit event is not done, regardless of demo quality.
- Version the adjudication rules. Rules are artefacts with effective dates, referenced by the audit record. Without rule versioning, 'consistent processing' is unprovable after the first rule change.
- Record boundary and data-ownership decisions in one-page decision records (context, options, decision, consequence) reviewed by architecture, so the next team inherits the reasoning rather than rediscovering it.
- Prove auditability with a drill. Given a claim ID and a date, reconstruct state and rule version from the audit stream, quarterly, without engineering help.
Success test: an auditor can reconstruct a claim unaided, and you can show the automated test that guarantees it.
3. What are the realistic options for the shared library and the duplicated member master, and what does each cost?
Read the worked answer
These are two different problems and should not be solved with one move.
Shared library (22 dependents):
- Thin, versioned contracts. Reduce the library to schemas, client stubs and backward-compatibility guarantees, with independent versioning so teams upgrade on their own schedule. Cost: discipline and a compatibility test suite.
- Duplicate and delete. Copy what each service needs and remove the dependency. Cost: divergence. Cheap if the library holds utility code, expensive if it holds business rules.
- Extract a service. Promote genuinely shared behaviour into an API. Cost: a network hop and a runtime dependency, so only correct for behaviour that must change in exactly one place.
Selection rule: does this code need to change together? If yes, extract a service. If it must be identical but stable, version a contract. If it is incidental, duplicate it.
Duplicated 'active status':
- Nominate one owning service as system of record, with an explicit status rule including effective dates. Others consume via events plus a query API.
- The cost is availability coupling, so mitigate with a cached read model and a published staleness bound - for example, status reads may be up to 60 seconds stale, and adjudication must re-check at the point of payment.
- A nightly batch reconciliation alone institutionalises the five-day month-end. Use reconciliation temporarily to prove convergence, alert on divergence, then retire it deliberately once the sample duplicate rate reaches zero.