Scalability & caching
Caching is the cheapest performance win in computing and the most dangerous one in healthcare — because a stale allergy list looks exactly like a fresh one.
In one line
Scaling is about handling more load without falling over. Caching is the cheapest way to do it — and in clinical systems it is the one optimisation that can quietly cause harm, because stale data looks exactly like fresh data.
The two axes
- Vertical — a bigger machine. Simple, immediate, and it runs out. There is a largest server.
- Horizontal — more machines. Effectively unbounded, and it forces you to confront state: if a request can land anywhere, where does the session live? Which node has the truth?
Health workloads have an unusual and rather pleasant property: the load is predictable. OPD opens, rounds happen at the same hour, shift changes are on a timetable, and the lab batch lands when it always lands. Unlike consumer traffic, you are rarely surprised. Scale for the known peak rather than the imagined one.
Caching, and the thing that makes it different here
Every layer can cache: browser, CDN, application, database query, DNS. The performance economics are irresistible — orders of magnitude cheaper than the alternative.
Now the health-specific danger, stated plainly:
A stale allergy list is indistinguishable from a current one.
There's no visual difference. No error. No degraded mode. The screen renders confidently and the clinician believes it, because believing the screen is exactly what we spent twenty years training them to do. A cached price on an e-commerce page being ten minutes old is an annoyance. A cached allergy, medication list, or lab result being ten minutes old is a decision made on fiction.
So the rule for clinical systems is a discipline, not a config value:
- Cache the catalogue, not the patient. Drug reference data, terminology value sets, templates, static content — cache all of it aggressively; it changes rarely and safely.
- Be extremely careful caching the chart. Allergies, current medications, results, and anything that drives an alert.
- If you must cache patient data, cache it briefly and invalidate on write. And know that invalidation is the part that will fail.
- Show the age. "As of 09:42" costs nothing and transfers the judgement to the human, who can decide whether ten minutes matters for this decision. That single line of UI is worth more than most cache tuning.
Invalidation, honestly
The old joke — that cache invalidation is one of the two hard problems — is a joke because it's true. The failure is never the cache; it's the write path that forgot to tell the cache. Someone adds a new way to update allergies six months later, doesn't know the cache exists, and now there are two sources of truth that disagree silently.
This is why cache invalidation is an architectural commitment, not a feature. If you can't enumerate every write path today, you can't safely cache what they write.
The rest of the toolkit
- Read replicas — excellent for reporting, and they lag. Never read a replica for a clinical decision without knowing the lag; "the database said so" is not reassuring if the database is three seconds behind reality.
- Queues (Kafka) — absorb bursts, decouple producers from consumers, and turn a thundering herd into a backlog you can watch.
- Connection pooling — usually where the real ceiling is, long before CPU.
- Async the slow thing — nobody needs the PDF generated inside the request.
The measurement point
Do not optimise what you have not measured. The bottleneck is almost never where the team believes; that's why observability precedes scaling. And measure the p99, not the mean — the average clinician has a fine experience while the one waiting eleven seconds is the one who stops trusting the system, and never tells you.