Sample Report · Architecture

Architecture Review — Sample

A worked example of reviewing a system against how it is actually used — where load and change concentrate, which couplings cost, and the recommendation that follows from evidence rather than from taste.

Markdown. No sign-up, no email.

This is an illustrative example. The system and figures are invented to show the shape of a review that produces decisions. Copy the structure; measure your own system.

The review deliberately avoids architectural preference. Every recommendation is supported by either an incident, a measurement, or a change-history count.


Architecture review — order platform#

SystemOrder capture, pricing, fulfilment, invoicing, reporting
Age6 years, 5 services, one shared database
MethodChange history, incident record, load measurement, dependency mapping
Prepared forEngineering leadership

1. How it is actually used#

Orders per day42,000
Peak, as a multiple of median hour3.1×
Read to write ratio40:1
Reporting queries per day900
Growth, 12 months18%

The read-to-write ratio is the most consequential number in this review, and it was not known before the review. The system is designed as though writes dominate, and reads — including every reporting query — go to the same database as order capture.

2. Where change concentrates#

ComponentShare of codeShare of changesIncidents
Pricing11%38%9
Order capture19%17%4
Fulfilment24%14%6
Invoicing18%21%3
Reporting28%10%2

Pricing changes constantly — it is where the business expresses itself — and it is the smallest component. It is also called synchronously by order capture, which is section 4.

3. Coupling#

CouplingTypeCost in the period
All 5 services → one databaseShared data store6 of 24 incidents
Order capture → pricingSynchronous9 incidents, all pricing-caused
Invoicing → fulfilmentSynchronous2 incidents
Fulfilment → carrier APISynchronous, external4 incidents
Reporting → the same databaseShared3 incidents

The shared database is the largest structural finding. Five services with no business relationship share a failure domain. Twice this year a reporting query has degraded order capture; on both occasions the reporting team was unaware of the incident and the order team had no way to see the cause.

4. The pricing coupling#

Worth its own section, because it produces the most incidents and the fix is not obvious.

Order capture calls pricing synchronously. Pricing changes most often. The most frequently changed component sits inside the availability path of the most business-critical one.

Pricing incidents in 12 months9
Of those, causing order capture to fail9
Median duration14 min
Orders lost or delayed~3,900

The naive fix — make it asynchronous — is wrong. A price is needed to accept an order; there is no meaningful order without one. This is a genuine coupling and the honest response is to make it bounded rather than to pretend it is not there.

Recommended instead: a timeout with an explicit fallback to the last published price list, plus a circuit breaker. The fallback is not as good as live pricing and it is much better than refusing orders. The business rule — how long a stale price may be used, and for which product categories — is a decision for the commercial team, not for engineering.

5. Load#

MeasuredProvisioned for
Order capture, peak340 req/min2,000
Pricing, peak340 req/min400
Reporting, peak90 queries/minshared
Database connections at peak780 of 800800

The connection pool is the binding constraint and nobody knew. At peak the system is 20 connections from refusing work, and the largest single consumer is reporting — long-running queries holding connections while order capture waits.

This also explains an unexplained class of incident: three "slow order capture" reports correlate exactly with a monthly reporting job.

6. What is working#

Recorded because a review of only problems produces a rewrite proposal.

  • Service boundaries follow the business. Order, pricing, fulfilment and invoicing are real domains, not layers. This is the hard part and it is right.
  • Order capture is idempotent. Duplicate submissions are handled correctly, which has prevented several incidents from becoming data problems.
  • The carrier integration has a timeout and a queue. The one external dependency is the best-protected boundary in the system.
  • Deployment is per service and has been for two years.

7. Recommendations#

  1. Separate reporting from the operational database. A read replica, with reporting pointed at it. Addresses 3 incidents, the connection-pool constraint, and the monthly correlation. Roughly two weeks and no application change.
  2. Bound the pricing call — timeout, fallback to the last published list, circuit breaker. Addresses 9 incidents. Needs a commercial decision on stale-price tolerance first.
  3. Give each service its own schema within the shared instance, as a step toward separate stores. Removes accidental cross-service queries, of which the review found 14.
  4. Raise the connection pool and alert at 80%. A one-line change that removes the current silent ceiling.
  5. Do not split pricing into smaller services. It changes often because the business changes often, not because it is too large. Splitting it would distribute a coupling rather than remove one.
  6. Do not rewrite fulfilment. It has 6 incidents and 14% of changes, and every one of the incidents traces to the carrier API rather than to the code.

Deliberately not recommended: a move to full service isolation with separate databases per service. Recommendations 1 and 3 capture most of the benefit for a fraction of the work, and the remainder can be argued when the first two have been measured.


Notes on using this format#

Measure how the system is used before reviewing how it is built. The 40:1 read-to-write ratio was unknown, and it reframed the entire review.

Count incidents per coupling. It converts "the shared database is bad practice" into "the shared database caused 6 of 24 incidents", which is a sentence that gets funded.

Say what not to change. Two of the six recommendations are refusals, and both are for components that look like obvious candidates and cost nothing.

Back to Architecture