Capability 28 · Performance Engineering

Performance Engineering

Fast everywhere — no matter the device, network or number of concurrent users.

Before you read: Written from live engineering practice — the money-moving, million-user work our team runs on our own products, set down so anyone building something can learn from it.

01 · What it is

Speed is a feature, and on Kenyan networks it's a loyalty feature — a slow app gets deleted. We engineer performance deliberately instead of discovering it at launch: load and stress testing that shows where it breaks before traffic does, query and index optimization so the database doesn't become the wall, caching at the right layers instead of everywhere cheaply, and performance budgets that hold the line as features multiply. We measure Core Web Vitals and app start times, and we test on slow networks, not just the office Wi-Fi — because the customer who matters is the one on the flaky connection.

What a performance engineering build covers:

  • Load & stress testing before launch, not after
  • Query & index optimization at the database layer
  • Caching placed at the right layers, not everywhere
  • Core Web Vitals & app start-time budgets
  • Performance budgets enforced as features are added
  • Tested on slow networks, not just office Wi-Fi
What we do · How we do it — as TGJOF Enterprise

This is how we do Performance Engineering

Performance is decided by the slowest path a user actually walks, not by the fastest one that looks good in a benchmark — and on patchy mobile networks that path is brutal. Measurable p99s and the worst case carry more weight than the average, so the discipline starts by finding the slowest endpoint and instrumenting it like a crime scene. Load testing happens before traffic arrives rather than after the first spike discovers the ceiling, and the budgets that hold the line live in CI alongside correctness. Speed only earns trust when it is a number that keeps being true in production.

What we do

  • The slowest path wins the budget — the endpoint and the screen that cost a real user the most time are the ones with the strictest targets and the deepest instrumentation, because the long tail the average hides is where users actually leave.
  • Measurable p99s, not feelings — latency is quoted in percentiles and enforced per endpoint, so 'fast enough' has a number CI can defend and a p95 slip fails the build.
  • Load testing before it hurts — realistic concurrency and throttled networks are fired at the system before launch, so the first peak meets a known ceiling instead of a surprise outage.
  • Budgets that gate every release — LCP, INP, start time, bundle weight and API latency carry explicit limits, and a feature that bankrupts a budget is rejected at review rather than discovered by users.
  • Profiling where users really are — production traces and flame graphs decide the fix rather than any hunch, and the same instrumentation that found the problem proves the fix moved the number.

How we do it

  • Find the slowest path first — the request and the screen that cost the most real time are identified up front, then made the most measured, most indexed and most cached surfaces in the product.
  • Kill the database ceiling early — hot queries are explained, indexed and stripped of N+1 loops while the table is still small, so the wall that ends product life has already been moved before scale arrives.
  • Cache what is safe, never the ledger — reference data and hot reads sit in short-TTL and edge caches while balances and statuses stay authoritative, invalidated atomically with the writes that change them.
  • Break it on purpose, on schedule — load, stress and recovery runs hammer the real queries, the real pool and a throttled network profile until the ceiling and the recovery curve are both known numbers.
  • Hold the line in production — hot paths are watched as live percentiles with error budgets and money-path alerting, so a drift becomes a papercut with a timeline and an owner instead of a month-end mystery.

02 · The full discipline

Users forgive a lot — except slowness. We engineer speed deliberately, on the networks real Kenyans actually hold.

A slow app is not a slow app; it is a product that got uninstalled, a checkout that got abandoned, an M-Pesa push that timed out with the customer staring at a spinner. Speed is not a polish pass you apply at the end; it is a budget you set at the start and a discipline you enforce as features ship. Users forgive many flaws — they do not forgive slowness.

We build performance engineering into every project we touch, and we run it as a live practice on our own payments platform. KodiiPay moves real money through M-Pesa on Safaricom's Daraja rails — STK Push, PayBill, C2B, B2B, B2C, Till — and it does that on prepaid Kenyan data bundles over networks that drop, flap and throttle. That is not a stress-test scenario we invented; it is the everyday reality the platform was designed for. We measure, profile, index, cache and load-test until the numbers hold, because a payment notification that arrives late — or a gateway callback that drags on any rail — is a customer who has already checked their M-Pesa statement and called support.

Below is how performance engineering is really done when your own product's reputation depends on it. Budgets, Core Web Vitals, profiling, database indexes, N+1 elimination, caching, CDN delivery, load testing and the monitoring that keeps it true in production — every layer is what we actually apply, and we bring the same machinery to every product we build for clients.

03

Speed is a feature — and on Kenyan networks it's loyalty

A product that is fast on office Wi-Fi but slow on the network your customers actually use is a product that is slow, full stop. In Kenya the network is the product's environment: prepaid data bundles, shared connections, 3G transitions, and phones that have been perfectly serviceable for years. We engineer for that reality from the first screen.

  • Load testing before traffic, not after — we hit the system with realistic concurrent load before launch, so the first big spike is not the first time the database learns about its own ceiling.
  • Query and index optimization as standing practice — slow queries are found and fixed as part of every release, not waited for until the month-end report crawls.
  • Tested on slow networks, not office Wi-Fi — throttled profiles for 2G, 3G and congested 4G are part of the test matrix, so 'fast in the office' and 'fast in the field' are the same sentence.
  • The cost of every megabyte is counted — bundled data costs real money, so payloads, images and round-trips are budgeted like money, because to a customer they literally are.
  • The first screen is the whole product — for a payments app the balance and the pay action must be visible and usable within seconds; everything else is engineered around that.
  • Slowness is measured as a business loss — a spinner during an STK push is not a cosmetic issue; it is a customer who doubts the money moved at all.

Speed is loyalty: a fast product gets the benefit of the doubt, a slow one loses it even when it is objectively better. We build speed in so the product keeps that benefit long after launch.

04

Users forgive a lot — except slowness

Every performance decision starts from one admission: people are impatient, and they are right to be. A form that takes eight seconds to respond reads as broken; a checkout that spins after the money left the wallet reads as lost money. The whole discipline of performance budgets exists because users will not explain their impatience — they just leave.

  • First input to response is a promise — the moment a user taps, something visible must happen; INP and first-input latency are treated as hard budgets, not aspirations.
  • The three-second rule is compressed on mobile — on prepaid data, with a backend that may be far from the user's tower, every added second multiplies the chance of abandonment.
  • Slow flows create support tickets — every slow screen is a future 'did my payment go through?' call; speed is a support-cost decision as much as a user-experience one.
  • Perceived speed is engineered too — optimistically rendered structure, immediate feedback and honest loading states keep the interface feeling alive even while real work happens behind it.
  • A regression is a bug — a feature that makes the app measurably slower is treated as a defect and fixed, not accepted as the price of the feature.
  • Speed is compared on the user's network — the target is not the ping to the data center; it is the time to first paint on a mid-range Android on a congested 4G evening in Nairobi.

We do not ask users to be patient; we earn their patience by making the product fast. When a user never notices the performance, that is the performance working.

05

Performance budgets that hold the line

A budget is only useful if it is enforced. We set explicit numbers for core Web Vitals, app start time, bundle size and API latency, and the CI pipeline refuses builds that blow them. Features that would bankrupt the speed you shipped with are caught at review time, not discovered by users at launch.

  • Core Web Vitals as release gates — LCP, INP and CLS have defined limits, and every release is measured against them before it ships.
  • Bundle budgets in the build — the JavaScript and asset payload has a maximum that is checked mechanically; a dependency that adds 300KB is a conversation, not a silent regression.
  • API latency budgets per endpoint — the hot endpoints (balance, history, pay) carry explicit latency targets, enforced with tests that fail when the p95 slips.
  • App start time budgeted — cold start from icon tap to usable screen has a number, and startup work is ruthlessly deferred, lazy-loaded or removed to hold it.
  • Budget expiry dates — a budget set at launch is revisited as users, data and features grow, so the line moves deliberately rather than being quietly abandoned.
  • Budgets are written down — the numbers live in the repo and the docs, so 'what are we trying to hold?' has a written answer, not a remembered one.

Budgets make performance reviewable the way security and correctness are reviewable. Without a number, 'it feels fast enough' is a feeling; with a number, it is a fact that CI defends.

06

What we actually measure: LCP, INP and the numbers that matter

You cannot engineer what you do not measure, and you cannot measure performance from a single number. We instrument the metrics that map to real user experience — the ones that decide whether a person stays on the page, completes the payment or gives up.

  • Largest Contentful Paint — does the main content visually arrive? LCP rendering within budget is a gate, because a blank screen is abandonment.
  • First Input Delay and INP — the time from tap to visible response is the number users feel most directly; we budget it on every interactive surface.
  • Cumulative Layout Shift — content that jumps under the cursor mid-payment is not just annoying; on a money form it can make someone pay twice or tap the wrong thing.
  • Time to Interactive on the critical path — the pay button, the balance, the retry — the money-critical controls are interactive fast even if the rest of the page loads lazily.
  • Server time versus network time — every request is split into time-in-the-backend and time-on-the-wire, because the two have completely different fixes.
  • p95 and p99, not just the average — the average hides the slow tail; the tail is where users actually leave, so it is what we track.

The metrics are chosen to mean something about a human sitting with a phone, not to make a dashboard look green. If the number does not predict whether a user stays or leaves, we do not cheer it.

07

Database performance: the index decides

Behind almost every 'the app got slow' is a database. The database is where the product's truth lives, and if reading that truth is slow, no amount of frontend polish helps. We treat query performance as a first-class engineering concern, the same way we treat correctness.

  • The hot paths are indexed before they are needed — the queries that run on every screen (pending-by-owner, transaction-by-reference, ledger-by-wallet) are discoverable and indexed while the volume is still small.
  • EXPLAIN before acceptance — every non-trivial query is read through the planner before it ships; a sequential scan on a growing table is caught at review, not at scale.
  • Composite indexes for real filters — indexes match the actual WHERE clauses users fire, not the columns a schema designer guessed would be popular.
  • Partial indexes for partial states — a query that filters on status='pending' gets an index that only covers pending rows, so the index shrinks as the pending pile does.
  • pg_stat_statements is read like a report — the slowest queries are reviewed regularly, so a query that degrades as data grows is found because someone looked at the numbers.
  • Indexes have a cost, so they earn their place — every index must justify its write overhead; bad indexes are dropped rather than worshipped for having once helped.

The database either scales with you or it becomes the wall you hit at the worst time. We index, profile and sanity-check so the wall arrives only when you deliberately decided to move it.

08

N+1 queries: the classic silent killer

The most common performance bug in the industry is also the quietest: a list screen that fetches the rows, then fetches related data for every row in a loop — one query for the list and one hundred for the details. It is invisible at ten rows and devastating at ten thousand.

  • Fetch what you render in one query — list screens read their related data with joins, batched IN queries or a single aggregation, never with a per-row lookup.
  • The loop that hides a query is hunted — code review looks for loops that touch the data layer; the pattern is named, searched for and caught mechanically where possible.
  • Batching is the default answer — when related data must be fetched separately, it is fetched once for the whole batch and correlated in memory, not once per item.
  • The query count is a budget — a screen that issues dozens of statements to render one view is a code smell with a number attached, and the number is a review comment.
  • Explain and measure, then refactor — the fix is guided by the plan and the timing, not by guessing which query is the culprit.
  • Tests catch it as a regression — a guard that flags a page's query count protects the refactor from being un-done by a later feature.

N+1 is the reason 'it worked in the demo' and 'it crawled in production' can describe the same screen. We kill the pattern at review so it never shows up in the demo.

09

Profiling before fixing

It is tempting to guess where the slowness is. Guessing wastes time and occasionally makes things worse. We profile first — in development, in staging and in production — and fix what the profiler proves, not what a hunch accuses.

  • Profiling in development for the obvious wins — render time, function hot spots and layer time are measured with tools that show the actual cost centers.
  • Profiling in production for the truth — production traces show real users, real devices and real networks; a profile from a developer's laptop is a hypothesis, not a fact.
  • Flame graphs over folklore — the time spent in a slow function is seen, not assumed; the fix targets the proven cost, not the famous suspect.
  • The waterfall of the request is read — where the time goes — DNS, connect, TLS, server, query, render — is visible layering, so the fix goes to the right layer.
  • A profile before and after — the fix is proven by the same instrumentation that found the problem; if the number did not move, the fix did not work.
  • Profiling is a habit, not an event — performance instrumentation lives in the normal workflow, so regressions are caught while their cause is still fresh.

Measure, then cut; never cut blind. The profiler decides, and when the profiler and the hunch disagree, the profiler wins.

10

Caching at the right layers

Cached data is fast data — if it is the right data at the right layer, with invalidation that actually works. A cache without a working invalidation strategy is a bug factory; a cache with one is one of the biggest speed wins available.

  • Cache the read-heavy truth, not the write-heavy ledger — the money balances and ledgers stay authoritative; the cache holds the reference data, the hot reads and the assembled screens.
  • HTTP caching for what barely changes — static assets, public reference data and anonymous shell content are cached at the edge with explicit, versioned keys.
  • Short-TTL caching for volatile-but-read-heavy state — the kinds of data that change often but are read constantly get a short, safe TTL rather than a long, dangerous one.
  • Cache invalidation is designed, not hoped — every cached key has an owner and a lifecycle; a stale value visible to a customer is a bug with a severity, not a shrug.
  • The money paths are never served from a stale cache — a balance or a transaction status is served from the ledger, or from a cache that is invalidated atomically with the write.
  • Cache hit ratio is a monitored number — a cache that misses all day is hardware doing nothing; the ratio tells us whether the layer is earning its complexity.

Caching done right is nearly free speed; caching done wrong is wrong data shown proudly. We build the layer and the invalidation together, because one without the other is a liability.

11

CDNs and the edge

Kenya's traffic, like the world's, crosses the internet in unpredictable ways. A CDN puts static and near-static content closer to the user, and the edge has uses well beyond images — it can terminate TLS, enforce rate limits and absorb the cost of many round-trips before the origin ever sees them.

  • Static assets move to the edge — the JavaScript, images, fonts and styles that make up the shell are served from a node near the user, not across the sea.
  • TLS is terminated early — handshakes happen at the edge, sparing the origin the cost of every secure connection from every device.
  • Rate limiting at the edge — abusive bursts are throttled before they reach the application, protecting the origin from floods that are never even legitimate traffic.
  • Origin shielding for the cold misses — the edge avoids stampeding the origin with dozens of requests for the same cold asset; the shield fetches once and distributes.
  • Cache headers are a contract — the origin tells the edge exactly what is cacheable and for how long; no guesswork lives as a heading that nobody owns.
  • Payments are not cached at the edge — the money endpoints are served from the origin, where the ledger and the verification live; the edge accelerates what is safe to accelerate.

The edge is a multiplier for the parts of the product that can be cached, and a firewall for the parts that must not be. We use it for both, deliberately.

12

Mobile-first networks: the Kenyan reality

An app that performs on fibre but stumbles on a prepaid 4G evening is an app that performs for the wrong audience. In Kenya the network is a first-class engineering input: bundles cost money, throughput fluctuates, towers congest, and a phone may sit on a 3G fallback for long stretches. We design for that reality, not against it.

  • Payloads are a cost customers pay — every asset is compressed, resized and deferred because every megabyte is paid for by the person holding the phone.
  • Offline and degraded modes are real — where it makes sense, the app works with a bad connection rather than refusing to: cached reads, queued actions and honest 'you are offline' states.
  • Retries are engineered, not hoped — the payment path retries against its gateways with exponential backoff and idempotency, so a dropped network mid-payment or a slow-returning callback is resolved, not abandoned.
  • The bundle is smaller on purpose — lazy-loading, code-splitting and the discipline of not importing the whole internet into one screen keep the initial payload honest.
  • Image pipelines deliver the smallest useful file — dimensions, quality and format are chosen per bucket, so a property photo is not shipped as a 6MB original to a phone that needs 120KB.
  • The data plan is part of the UX copy — where an action is heavy (download, upload, sync), the product tells the user what it will cost, because in Kenya data is not free.

The best optimization is the request you never send; the second best is the request you send once. Mobile-first performance is that discipline applied every day on the networks real users hold.

13

Image, payload and network frugality

Images are the heavyweight of the modern web and the easiest win. A photo that is not resized, compressed and lazily loaded is a bill the customer pays on every visit. We build the asset pipeline so the right file arrives at the right size without anyone having to think about it.

  • Downscale to the display — images are resized close to the size they are rendered at; the 4MB camera original is never shipped to a 300px thumbnail slot.
  • Modern formats with ancient fallbacks — progressive formats serve where supported, with a fallback that keeps older devices rendering correctly.
  • Lazy loading below the fold — images off screen are not loaded until they scroll near; initial page weight drops without the user noticing anything.
  • Compression is a pipeline, not a manual chore — every upload passes through the same compression step so no future developer has to remember to press the optimize button.
  • Re-encoding for push and display — banner images in notifications and chat thumbnails are prepared at the small size they are actually shown at.
  • A weight budget per page — the total bytes for a screen is a number the team knows, and new assets are measured against it.

Every kilobyte travels through a Kenyan data bundle before it reaches a customer. We respect the budget as if it were money — because to the user, it is.

14

Concurrency and connection handling

Performance is not only about fast single requests; it is about many requests at once. What feels like 'the app slowed down' at 5pm may be a server that cannot multiplex, a connection pool that exhausts, or a query that holds a lock while forty others queue behind it.

  • Connection pools sized, not defaulted — the pool matches the real concurrency profile of the traffic, so slow endpoints cannot starve fast ones of connections.
  • Locks measured for hold-time — the money-safe locks (FOR UPDATE on wallets) are held for the shortest transaction that is still correct, so contention is a designed trade-off, not an accident.
  • Heavy work moves off the request thread — emails, notifications and report generation are queued and processed asynchronously, not serialized into the customer's request.
  • Batching for the crons — scheduled jobs drain in bounded batches with advisory locks and SKIP LOCKED, so a million-row sweep does not hold the database hostage.
  • Timeouts everywhere, with honest defaults — every upstream call has a timeout and a defined consequence; no customer request waits forever on a partner that forgot to answer.
  • The slow tail is resource-bound — p99 regressions are investigated as resource constraints (threads, connections, memory, locks), not mysterious degrading of one lucky endpoint.

Performance at one user is a demo; performance at a thousand concurrent users is engineering. We design the concurrency posture before the spike proves it necessary.

15

Scale without the ceiling

A system that is fast for hundreds but slow for millions was built to a number someone picked in a meeting. We design and measure for growth so performance holds as users multiply — and we are honest about which number will be the first wall, so it is never a surprise.

  • Stress and concurrency testing at realistic peaks — the monthly rent spike, the payday surge, the viral moment — the load is simulated before the real thing arrives.
  • Bottleneck planning before the wall is hit — we know which component will be the first constraint (database, connection pool, worker count) and what the escalation path is.
  • A staircase of scale, not a single cliff — growth is met by staged improvements (index, cache, read replica, partition) rather than one catastrophic rewrite at the moment of demand.
  • Data growth is modelled — a query that is fine at 100K rows is not expected to blow up silently at 10M; the growth curve is part of the design.
  • Reads can be split from writes where it pays — hot reporting and dashboards are served from dedicated paths so analytics cannot slow down the money-making writes.
  • The million-user question is asked now — 'what happens at ten times the load?' is a standing question in design review, not a question we hope never to be asked.

Scale is not a feature you buy; it is a property you design and prove. We build for the ceiling you intend to reach and keep the ladder approved before you need it.

16

Load and stress testing before traffic

The worst time to discover the ceiling is the moment traffic arrives. Load testing is how a system learns its own shape — how many users it serves at target latency, what breaks first, and exactly what the recovery looks like when it does.

  • Realistic scenarios, not synthetic kindness — the test runs the real user paths (login, balance, pay, list) at realistic mix, not a single perfect endpoint.
  • The network profile matches the audience — throttle and latency are applied so the test reflects a Kenyan evening, not a localhost loopback.
  • The breaking point is found deliberately — the test pushes until something degrades, so the ceiling is a known number with a known shape, not a mystery.
  • The database is under the same load — the test exercises the real queries, the real indexes and the real connection pool, because those are where ceilings usually live.
  • Recovery is tested, not assumed — what happens when the load drops — pools reprime, queues drain, the tail recovers — is proven.
  • Results are written into the plan — the measured capacity becomes the input to infrastructure sizing, so the environment matches the reality the test measured.

A load test that passes is a floor, not a ceiling — but a load test that never ran is a leap of faith. We prefer the floor we measured.

17

Monitoring latency as a live number

Performance is a running property, not a launch-day certificate. Between launches, features land, data grows and the network shifts; only live monitoring tells you whether the number you shipped is still the number you are running.

  • Latency dashboards for the hot paths — the money endpoints and the first-screen render are watched as live numbers with percentiles, not anecdotes.
  • Error budgets with a consequence — the acceptable error-and-latency budget is written down, and exceeding it is an on-call event, not a Friday-note.
  • Trends get a review — a slow drift upward over weeks is caught and investigated while the cause is small, not after a month of compounding.
  • Real user monitoring for the client side — the time a real device takes to reach a rendered, interactive screen is visible from actual users, not lab estimates.
  • Alerts tuned to the money — the payment path has its own alerts, so a rent-day slowdown pages a human instead of hiding in a general-purpose dashboard.
  • A regression is a ticket with a timeline — when a number breaks, there is a recorded before and after, so 'what changed' has a searchable answer.

Performance without monitoring is a promise nobody checks. We monitor so the promise stays true and a drift is a papercut with a timeline, not a mystery at month end.

18

Honest limits of performance engineering

Performance engineering is powerful and it has honest boundaries. We will tell you what it cannot do, because the discipline is worth more when it is honest about its own ceiling.

  • Speed cannot rescue a product that does not do the job — a fast product that solves the wrong problem loses to a slower one that solves the real one.
  • The network you cannot control — between the tower and the customer there are operators, backhauls and throttles that no index or cache fixes; we optimize what is ours and design tolerantly around what is not.
  • Every optimization has a cost — caching adds invalidation complexity, indexes add write overhead, and the edge adds a moving part; each is chosen for a measured reason, not for fashion.
  • There is no end to performance work — the codebase, the data and the traffic keep growing, so the budget, the profiling and the monitoring are a standing practice, not a finished task.
  • Perceived performance is partly human — users judge speed partly by feedback and framing; we engineer the real numbers and the honest feedback together.
  • The first bottleneck is often not where you feared — the profiler decides; the fear and the fix can disagree, and the profiler wins.

We will tell you honestly when your product does not need an elaborate cache hierarchy — and give you the smallest correct performance posture. And when it does need the real machinery, this is the real machinery.

The toolchain

The performance engineering toolchain

The exact instrumentation, profilers, index tooling, caching layers and load harnesses we run — the same machinery we use on a live payments platform that must be fast on Kenyan networks.

stack.toolchain

01

Budgets & metrics

The numbers that hold the line

  • Core Web Vitals instrumentationLCP, INP and CLS measured as real-user numbers with budgets enforced in CI.
  • Bundle analysisThe shipped JavaScript and asset payload is measured and budgeted so dependencies cannot silently double the weight.
  • CI performance gatesBuilds that blow a budget are rejected at review time, not discovered by users at launch.
  • Startup timingCold start from icon tap to usable screen is measured as a budget on every mobile surface.
  • API latency budgetsPer-endpoint p95 targets that fail the test run when the tail slips.
  • Real user monitoringField data from actual devices on actual networks, not lab estimates.

02

Profiling

Find the truth before the fix

  • Tracing & flame graphsThe request's actual time distribution is visible, so the fix targets the proven cost center.
  • Layer time analysisThe request waterfall splits network, TLS, server, query and render time into individually fixable pieces.
  • Production tracesReal traffic, real devices, real concurrency — profiling where users actually are.
  • Heap and GC analysisMemory leaks and allocation storms are found and fixed before they become latency.
  • Slow-path instrumentationThe money endpoints carry their own tracing so a rent-day slowdown is identifiable to the query.
  • Before/after proofEvery fix is verified by the same instrumentation that found the problem.

03

Database

The truth must be fast to read

  • EXPLAIN / query planningEvery non-trivial query is read through the planner before it ships; sequential scans are review comments.
  • pg_stat_statementsThe slowest statements are read as a standing report, so degradation is caught while small.
  • Composite indexesIndexes match the real WHERE clauses users fire, not guessed columns.
  • Partial indexesStatus-filtered queries get indexes that only cover the interesting subset, keeping them small.
  • Long-query guardsA query that exceeds its budget trips a test that fails the build.
  • N+1 detectionThe per-row lookup pattern is flagged in review and caught mechanically where possible.

04

Caching

Fast reads, honest invalidation

  • HTTP cache layersVersioned, explicit cache headers tell the edge exactly what is cacheable and for how long.
  • CDN / edge deliveryStatic shell, TLS termination and rate-limiting at the edge keep the origin for the origin's real work.
  • Short-TTL cachesRead-heavy, volatile state served with a safe short TTL instead of a dangerous long one.
  • In-process cachesHot reference data served from memory where it is genuinely safe and fast.
  • Atomic invalidationCached keys are invalidated in the same transaction as the write that changed them, or not cached at all.
  • Hit-ratio monitoringThe cache proves it is earning its complexity by the ratio it actually serves.

05

Networks & delivery

The payload is the bill

  • Image pipelinesEvery upload re-encoded, resized and compressed for the size it is rendered at.
  • Code-splitting & lazy loadingThe initial bundle carries only what the first screen needs; the rest arrives on demand.
  • CompressionTransfer encoding and modern formats served with fallbacks for older devices.
  • Offline & degraded modesCached reads and queued actions keep the product usable when the network is not.
  • Network throttling profiles2G, 3G and congested-evening simulations are part of the standard test matrix.
  • Data-cost-aware UXHeavy actions tell the user what they will cost, because bundles are paid for.

06

Load & stress

The ceiling is found on purpose

  • Load generatorsReal user paths driven at realistic mix, under realistic throttle and latency.
  • Concurrency harnessesWallets, queues and pools hammered exactly where they will contend.
  • Breakpoint discoveryThe test pushes until something degrades so the ceiling is a known number.
  • Recovery testsWhat happens when load drops — pool reprime, queued work drains — is proven, not assumed.
  • Database-under-loadThe real queries, indexes and connection pool are under the same pressure as the code.
  • Capacity planning inputMeasured results size the infrastructure, so the environment matches reality.

07

Monitoring

The promise stays true in production

  • Latency dashboardsHot paths and money endpoints watched as live percentile numbers.
  • Error budgetsThe acceptable error-and-latency envelope is written down and exceeded = on-call.
  • Trend alertsSlow upward drift is paged while the cause is small, not after a month of compounding.
  • Payment-path alertingThe money endpoints have alerts of their own, separate from general-purpose dashboards.
  • Regression timelinesA broken number has a recorded before and after, so 'what changed' is searchable.
  • Runbook-backed incident responseThe slow-tail investigation is documented, so the next incident is faster than the last.

Lifecycle

The performance engineering lifecycle — from budget to production truth

Performance is a standing discipline, not a launch-day polish. This is the lifecycle every product we performance-engineer passes through — including the one we run ourselves on a live payments platform.

01

Set the budgets

Explicit numbers for LCP, INP, CLS, start time, bundle weight and API p95, written into the repo.

02

Baseline & profile

Measure the current truth in development and production; find the proven cost centers before fixing.

03

Fix the database first

Index the hot paths, read the plans, kill the N+1s — the back end is where most ceilings live.

04

Optimize the payload

Images, bundles, compression and deferred loading — every kilobyte is a customer's data bundle.

05

Layer the caching

Edge, HTTP and short-TTL caches placed deliberately, each with invalidation designed, not hoped.

06

Harden concurrency

Pools, locks, timeouts and async queues sized and proven so slow work cannot starve fast work.

07

Load test

Real user paths at realistic mix over throttled networks until the ceiling is a known number.

08

Prove recovery

Verify pools reprime, queues drain and the tail recovers when load drops.

09

Monitor in production

Hot paths and money endpoints watched as live percentile numbers with the money-path alerts.

10

Enforce in CI

Budgets become gates; a feature that bankrupts speed is rejected at review, not discovered by users.

11

Revisit the budgets

As users, data and features grow, the numbers are re-derived deliberately rather than abandoned.

12

Keep proving it

Performance is a standing practice — profile, index, cache, test, monitor — as long as the product runs.

Closing

More than development

Performance engineering is the difference between a product that feels alive and one that feels broken — and on prepaid Kenyan networks it is the difference between loyalty and uninstall. When we engineer performance, that includes:

Performance budgets enforced in CI — LCP, INP, CLS, start time and bundle weight.Load and stress testing before traffic arrives, at realistic peaks.Slow-network testing as a standard, not a special case.Database index optimization as standing practice.N+1 query elimination at review and in tests.Profiling before fixing, with production traces for the truth.Caching placed at the right layers with working invalidation.CDN and edge delivery for what is safe to accelerate.Image and payload pipelines that respect the user's data bundle.Offline and degraded modes for the networks that drop.Concurrency and connection discipline under real spikes.Scale planned as a staircase, not a single cliff.Monitoring latency as a live number with error budgets.Payment-path alerting so a money slowdown pages a human.The honest tool chain: measured, proven, justified.Recovery tested, never assumed.Budgets revisited deliberately as the product grows.The discipline run live on a payments platform that must be fast when money moves.A written number for every promise, so 'fast' is a fact, not a feeling.You own the instrumentation, the budgets and the monitoring truth.

Users forgive a lot — loading spinners, occasional errors, a feature that misses by a mile. They do not forgive slow. Everything above exists to make sure the product earns the forgiveness it gets.

We measure what we ship and we ship what we have measured. When speed matters — and it always does — your product gets the discipline that survived being live, not the one that survived a lab.

Previous capability

Quality Assurance

Next capability

Accessibility

Building something like this?

The discipline above is what we run on our own products every day. If it would help on yours, our door is open.