~ Mohan Sankaran.
From monolith to platform
Every successful payments app starts life as a tidy monolith: one repo, one deploy, everything close to everything else. Then growth happens. New markets, new instruments, new risk checks. “Simple” changes fan out across billing, ledger, KYC, fraud, and notifications. Release trains slow. Reliability becomes a game of chance. The way out isn’t a rewrite for its own sake-it’s a platform mindset. Break the monolith along clear domain seams (identity, accounts, risk, payments, ledgers), give each boundary its own data and uptime budget, and let services evolve at their natural speed.
From endpoints to a graph
Mobile clients hate chatty APIs. They don’t want five round trips to build one screen; they want exactly the data they’ll render, in one call, shaped for the UI. That’s where GraphQL earns its keep. Instead of shipping a tangle of versioned REST endpoints, you publish a schema-a typed contract that describes everything clients can ask for. Screens query exactly the fields they need; nothing more. You keep REST where it shines (webhooks, file transfers, long-lived resources), but the app’s day-to-day traffic flows through the graph.
From backend sprawl to a single source of truth
Microservices are amazing for teams and awful for clients-unless you add a layer that hides the sprawl. A GraphQL gateway becomes that single front door. Behind it, resolvers fan out to services like Risk, Wallet, and Ledger. On the edge, the client sees one stable schema that changes additively. You can evolve internals, split services, even change storage engines, and the app keeps working. For larger estates, schema stitching or federation lets multiple teams own subgraphs without stepping on each other’s toes.
From synchronous calls to events
Payments are workflows, not functions-provision card, verify identity, score risk, capture funds, settle. Synchronous chains make every hiccup a customer problem. Switch to event-driven patterns. A payment intent is created, published on a stream, and downstream services react: risk scores, ledger postings, receipts. If anything fails, sagas compensate: reverse a hold, roll back a balance, mark a dispute. With idempotency keys and correlation IDs, retries are safe and traces are readable. The result is a system that bends under load instead of snapping.
From schema to contract
The GraphQL schema isn’t documentation-it’s the contract. Treat it like code. Lint it for naming and nullability. Deprecate fields with dates and migration notes. Generate type-safe clients for iOS, Android, and the web so UI code can’t accidentally misuse data. Use persisted queries to lock down what the app is allowed to execute and to speed cold starts on high-latency networks. In review, change the schema first, then land backend logic, then let clients opt in behind feature flags. No flag? No behavior. That discipline keeps rollouts boring.
From blocking to streaming
Some screens want live truth-pending transactions, settlement status, device pairing. Polling punishes batteries and networks. Add subscriptions over WebSockets or server-sent events to stream changes as they happen. On mobile, keep it pragmatic: reconnect with backoff, batch updates into local stores, and always present a consistent cached view so the UI never blinks. If the stream drops, the app should degrade to fresh-enough state, not a spinner.
From gateways to the edge
A great gateway owns more than routing. It enforces auth, rate limits, query cost (so one pathological request can’t DoS the farm), and data masking for sensitive fields. It also speaks mobile’s language: versioned headers for capabilities, locale/region hints, and A/B experiment IDs so the same schema powers controlled rollouts. Pair it with a BFF (Backend-for-Frontend) layer when a particular client needs orchestration the whole platform shouldn’t carry.
From deployments to delivery
Reliability is a release practice. Ship with blue/green or canary deployments, guard new resolvers with flags, and watch real-time health before widening exposure. Microservices get semantic versioning and backward-compatible payloads; events get versioned schemas and consumers that ignore unknown fields. The outbox pattern ensures changes write once and emit exactly once, even during node crashes. For mobile, assume the app will lag on updates-keep old fields alive and runnable for a long time.
From metrics to meaning
Observability ties it all together. Emit structured traces across gateway and services so a single transaction ID follows the whole journey. Track p95/p99 latency per field, error classes by resolver, and backpressure on event consumers. Build SLOs around user experience-“time to first balance,” “time to payment confirmation”-not just CPU charts. Feed the same telemetry to risk models so fraud scoring learns from the real shape of sessions: retries, jitter, out-of-order taps, and device integrity signals.
From caution to confidence
The promise of microservices and GraphQL isn’t “modern for modern’s sake.” It’s safety and speed at the same time. Services let teams move independently; events let failures localize; the graph gives clients exactly what they need; strong contracts and rollout hygiene keep everyone honest. For mobile financial platforms-where a slow screen is a lost sale and a broken flow is a broken brand-that combination isn’t a nice-to-have. It’s the foundation.
Ship the schema first. Guard with flags. Prefer events. Measure what users feel. When you get those right, the architecture fades into the background and the product feels simple-even when the system is anything but.
Leave a Reply