Research · Technological University of Panama

Web Application
Scalability Heuristics

A systematized catalog of 36 design principles derived from a frequency analysis across 17 academic and industry sources. The heuristics are ordered by degree of consensus across the reviewed literature.

16 Primary heuristics
consensus ≥ 15%
20 Secondary heuristics
consensus < 15%
10 Design
categories

Select a heuristic from the sidebar to get started.

Categories

Database 7
Architecture 5
Fault Tolerance 5
Horizontal/Vertical Scaling 5
Monitoring & Observability 4
API Design 4
Cache 2
CI/CD & Deployment 2
Load Balancing 1
Frontend/Client 1
H01 Cache Primary

Use caching for frequently accessed data

Temporarily store the results of expensive operations or frequently queried data in a caching layer (such as Redis or Memcached) to avoid recalculating them or fetching them from the database on every request.

Consensus index 47.1%
Mentioned in 8 of 17 sources · 3 academic · 5 industry

Detailed explanation

The database is typically the most common bottleneck in web applications under load. Every time a user requests the same data, running a full query wastes CPU time, disk I/O, and network connections. Caching solves this by storing the result in memory for a set period, so subsequent requests resolve in microseconds instead of milliseconds. It applies to frequent query results, user sessions, configuration data, responses from external APIs, and any data that changes rarely but is read often. The key is defining a proper invalidation policy: when does the data expire? Is it invalidated by time (TTL), by event (when the record updates), or both? A poorly configured cache can serve stale data, so the invalidation strategy is just as important as the storage strategy.

Practical example

A user profile is queried on every page. Instead of running SELECT * FROM users WHERE id=? on every request, the result is stored in Redis under a key like user:123 with a 10-minute TTL. 95% of requests are resolved from memory without touching the database.

H02 Cache Primary

Use a CDN or edge computing to serve content close to the user

Distribute static assets (images, CSS, JS, videos) and, in some cases, API responses across a network of geographically distributed servers (CDN), so each user receives content from the node closest to their location.

Consensus index 47.1%
Mentioned in 8 of 17 sources · 2 academic · 6 industry

Detailed explanation

Network latency is proportional to the physical distance between the user and the server. If your server is in Virginia and your user is in Tokyo, every request incurs a round trip of hundreds of milliseconds just from the speed of light. A CDN replicates your assets across dozens or hundreds of points of presence (PoPs) around the world, so a user in Tokyo receives the image from a server in Osaka. This reduces perceived latency, offloads the origin server from serving static files (which can account for 70-80% of total requests), and improves availability because content stays accessible even if the origin server has issues. Services like Cloudflare, AWS CloudFront, or Fastly let you configure this with minimal changes to application code.

Practical example

Netflix built its own CDN (Open Connect) inside ISPs to eliminate public internet traffic. This lets it serve billions of hours of video per month with minimal latency without depending on third-party CDNs.

H03 Monitoring & Observability Primary

Implement logging and distributed tracing

Systematically log system events and correlate those logs with a unique request identifier that travels through every service involved in processing it, allowing the full path of any request to be reconstructed.

Consensus index 35.3%
Mentioned in 6 of 17 sources · 3 academic · 3 industry

Detailed explanation

In a distributed system, a user's request can pass through a load balancer, a web server, three different microservices, and two databases before returning a response. When something fails or is slow, knowing exactly where the problem occurred is impossible without traceability. Logging records what happened; tracing correlates those events under a single ID. Tools like OpenTelemetry, Jaeger, or Zipkin let you visualize a request's full tree, see how long each service took, and pinpoint the service responsible for a degradation. Without this, debugging production issues becomes guesswork. This heuristic isn't only for when things break: traces also reveal latent inefficiencies that don't produce errors but do degrade the user experience.

Practical example

A request reaches the API gateway in 800ms when it should take 50ms. Distributed tracing reveals that the inventory microservice is calling the database 47 times instead of once, due to an N+1 query problem introduced in the last deploy.

H04 Architecture Primary

Design stateless services

Design each service or server instance so it doesn't store session information or local user state between requests. All necessary state should live in a shared external store (database, cache, JWT token).

Consensus index 29.4%
Mentioned in 5 of 17 sources · 2 academic · 3 industry

Detailed explanation

If a server keeps a user's session in its local memory, that user must always be routed to the same server. This creates session affinity (sticky sessions), which prevents load from being freely distributed across instances. If that server fails, the session is lost. If you need to add capacity by adding more servers, the load balancer has to track which user goes to which server, adding complexity. A stateless service eliminates all these problems: any instance can handle any request because it doesn't depend on local memory. User state lives in Redis or in a self-signed token (JWT) that the client sends with every request. This makes horizontal scaling trivial: adding more instances is simply spinning up more copies of the same service.

Practical example

Instead of storing the session in PHP's $_SESSION (which lives on the local server), a signed JWT is issued at login. Every request includes that token; the server verifies it cryptographically and extracts the user's identity without querying any session store.

H05 Architecture Primary

Split the application into loosely coupled modules

Organize code and services into independent units with well-defined responsibilities that communicate through explicit interfaces (APIs, events), minimizing direct dependencies between modules.

Consensus index 29.4%
Mentioned in 5 of 17 sources · 2 academic · 3 industry

Detailed explanation

A monolithic system where everything is interconnected scales poorly because any change can affect any other part, deployments are all-or-nothing, and a failure in one component can bring down the entire system. Modularity solves this by establishing clear boundaries: each module (or microservice) has a single responsibility, exposes a stable interface, and can be deployed, scaled, and updated independently. Low coupling means that if the payments module needs to scale because of a promotion, you can spin up more instances of just that module without touching the rest of the system. High cohesion means each module groups related logic, making the code easier to understand and maintain. This decision should be made from the initial design: separating modules in an already-built system is much more costly than designing them separately from the start.

Practical example

An e-commerce platform splits its logic into catalog, cart, payments, and shipping modules. During Black Friday, only the payments module needs to scale 10x. The rest of the system remains unchanged. If the shipping service fails, users can still browse and buy.

H06 Database Primary

Properly index frequently queried columns

Create database indexes on columns that frequently appear in WHERE, JOIN, ORDER BY, or GROUP BY clauses, so the database engine can locate relevant rows without scanning the entire table.

Consensus index 29.4%
Mentioned in 5 of 17 sources · 3 academic · 2 industry

Detailed explanation

Without indexes, a query like SELECT * FROM orders WHERE user_id = 123 on a table with 10 million rows means reading every single row to find the matches. With an index on user_id, the database engine can directly locate the relevant rows in logarithmic time. This can reduce a query's runtime from seconds to milliseconds. However, indexes aren't free: they take up disk space and slow down write operations (INSERT, UPDATE, DELETE) because every write must also update the corresponding indexes. The key is to index selectively: columns frequently read, while avoiding indexing columns that are written often but rarely read. Tools like EXPLAIN in MySQL/PostgreSQL reveal whether a query is using indexes or doing full table scans.

Practical example

An analytics application queries events by user_id and timestamp. Without an index, the query takes 4.2 seconds on a table of 50M records. Adding a composite index (user_id, timestamp), the same query takes 8 milliseconds.

H07 Fault Tolerance Primary

Design assuming components will fail

Build the system from the start under the assumption that any component — servers, databases, external services, network connections — can fail at any moment. The design must ensure the system keeps working (even if in a degraded form) when those failures occur.

Consensus index 23.5%
Mentioned in 4 of 17 sources · 2 academic · 2 industry

Detailed explanation

In distributed systems, partial failure isn't the exception, it's the norm. AWS, Google, and Netflix regularly publish post-mortems of incidents where individual components failed. The difference between a well-designed system and a poorly designed one isn't whether it fails, but how it fails. A fragile system fails completely when one component fails. A resilient system fails gracefully: if the recommendations service is down, the user can still browse the catalog, just without personalized recommendations. Concrete techniques include: circuit breakers (stop calling a failing service to avoid collapsing the chain), retries with exponential backoff (retry with increasing wait times), bulkheads (isolate resources so a failure doesn't consume all threads), and fallbacks (default responses when a service doesn't respond).

Practical example

Netflix practices chaos engineering (Chaos Monkey), randomly shutting down instances in production during work hours. This forces teams to design services that survive failures, because they know failures will happen.

H08 Load Balancing Primary

Use load balancing to distribute traffic

Place a load balancer in front of server instances that distributes incoming requests among them using some algorithm (round-robin, least connections, IP hash), preventing a single instance from receiving more traffic than it can handle.

Consensus index 23.5%
Mentioned in 4 of 17 sources · 1 academic · 3 industry

Detailed explanation

A single server has a physical limit on the concurrent requests it can handle. Load balancing lets you exceed that limit by distributing work across multiple instances. Besides distributing load, the balancer acts as a control point: it can detect unresponsive instances and stop sending them traffic (health checks), enable zero-downtime deploys by routing traffic only to already-updated instances (rolling deployments), and terminate SSL connections centrally. There are network-level balancers (L4, like AWS NLB) that operate over TCP/UDP, and application-level balancers (L7, like AWS ALB or nginx) that can route based on URL paths, headers, or body content. The choice depends on the complexity of routing required.

Practical example

Three web server instances handle traffic. The balancer detects that instance 2 isn't responding to health checks and stops sending it traffic within 30 seconds, without users noticing any service interruption.

H09 Database Primary

Use database replication to separate reads from writes

Maintain a primary database node that receives all writes, and one or more replica nodes that replicate data from the primary and handle read queries, distributing load across multiple servers.

Consensus index 23.5%
Mentioned in 4 of 17 sources · 2 academic · 2 industry

Detailed explanation

In most web applications, 80-90% of operations are reads. If all reads and writes go to the same server, that server quickly becomes a bottleneck. Replication separates these workloads: the primary node focuses on writes (which require consistency and transactions), while several replica nodes serve reads in parallel. The result is that read capacity scales horizontally by adding more replicas, without increasing load on the primary. The main consideration is asynchronous replication: there's a small delay (replication lag) between when something is written to the primary and when it appears on the replicas. For most use cases this is acceptable, but operations that need to immediately read what they just wrote should be directed to the primary.

Practical example

A news platform has a primary node for editors to publish articles, and three read replicas serving the public pages. A traffic spike from a viral story only affects the replicas; the publishing system remains stable.

H10 Horizontal/Vertical Scaling Primary

Prefer horizontal over vertical scaling

Design the system to grow by adding more instances (servers, containers) rather than making the existing server more powerful. Horizontal scaling allows for practically unlimited growth and greater fault tolerance.

Consensus index 17.6%
Mentioned in 3 of 17 sources · 2 academic · 1 industry

Detailed explanation

Vertical scaling (scale-up) has a physical limit: there's a maximum server you can buy, and each capacity jump is a downtime event or a disproportionate cost. Horizontal scaling (scale-out) has no such limit: if you need more capacity, you add more identical instances. Also, a single large server is a single point of failure; ten small servers can lose one without interrupting service. The prerequisite for horizontal scaling is that the system be stateless (H04) and that shared data be externalized. It isn't always the right answer for everything: a transactional database is harder to scale horizontally than a web server. That's why this heuristic mainly applies to the application layer, where it's more natural and less costly to implement.

Practical example

During the World Cup, a stats application goes from 5 to 50 instances in 10 minutes using autoscaling. Once the event ends, it scales back to 5. With vertical scaling, that spike would have required migrating to a server 10x more powerful, with hours of downtime.

H11 Horizontal/Vertical Scaling Primary

Process heavy tasks asynchronously

Move time-consuming operations (sending emails, generating reports, processing images, calls to slow external APIs) out of the request-response cycle by placing them in a queue that executes them in the background.

Consensus index 17.6%
Mentioned in 3 of 17 sources · 1 academic · 2 industry

Detailed explanation

When a user makes an HTTP request, keeping them waiting 30 seconds while a video is processed is unacceptable and blocks a server thread the entire time. Message queues (RabbitMQ, AWS SQS, Redis Queue) separate accepting the work from executing it. The server accepts the task, enqueues it, and responds to the user immediately (202 Accepted). Independent workers pull tasks from the queue and process them in the background. This has multiple benefits: the user gets an immediate response, web server threads are freed up to handle other requests, workers can scale independently based on queue volume, and if a worker fails, the task goes back to the queue to be processed by another. It also absorbs traffic spikes: if a thousand simultaneous requests arrive, the queue stores them and workers process them at their own pace.

Practical example

Upon signing up, a user receives a welcome email. Instead of calling the SMTP server during the request (adding 300ms), the send is queued. The user sees the signup confirmation in 50ms; the email arrives seconds later.

H12 Horizontal/Vertical Scaling Primary

Use serverless computing to scale automatically

Implement application components as serverless functions (AWS Lambda, Google Cloud Functions, Vercel Functions) that run on demand, automatically scale from zero to thousands of instances based on traffic, and only incur cost when they execute.

Consensus index 17.6%
Mentioned in 3 of 17 sources · 1 academic · 2 industry

Detailed explanation

The serverless model transfers infrastructure scaling responsibility to the cloud provider. Instead of keeping servers running 24/7 waiting for requests, each function invocation spins up its own execution environment, processes the request, and terminates. Scaling is automatic and instant: if a thousand simultaneous requests arrive, a thousand instances of the function run in parallel. This is especially useful for variable or unpredictable workloads, low-frequency APIs where keeping a server running isn't cost-effective, and background event processing. Limitations include cold-start latency (the first invocation can be slower), execution time limits, and higher cost per invocation compared to dedicated instances when traffic is very high and constant.

Practical example

A startup processes user-uploaded images with a Lambda function. With 10 users a day, the cost is practically zero. When a viral campaign drives traffic to 100,000 uploads in an hour, the function scales automatically without manual intervention.

H13 Monitoring & Observability Primary

Continuously monitor key system metrics

Collect and visualize the system's core metrics in real time — response latency, error rate, CPU and memory usage, throughput — with automated alerts that notify when critical thresholds are exceeded.

Consensus index 17.6%
Mentioned in 3 of 17 sources · 1 academic · 2 industry

Detailed explanation

You can't scale what you don't measure. Continuous monitoring lets you catch problems before users report them, spot growth trends for capacity planning, and confirm that architectural changes actually improve performance. Core metrics are grouped into Google SRE's four golden signals: latency (how long the system takes to respond), traffic (how many requests per second it processes), errors (what percentage of requests fail), and saturation (how full the system is, in CPU, memory, or disk). Tools like Prometheus, Grafana, Datadog, or AWS CloudWatch let you collect these metrics, visualize them in dashboards, and set up alerts. Without monitoring, you're operating blind: problems are discovered when users complain, not when they start.

Practical example

An alert fires when P95 latency exceeds 500ms. The team investigates and finds that a query without an index was introduced in the last deploy. The change is reverted before 99% of users notice.

H14 Database Primary

Choose the right database type for the use case

Select the database engine whose data model and consistency guarantees align with the system's access patterns, rather than always defaulting to a relational database.

Consensus index 17.6%
Mentioned in 3 of 17 sources · 2 academic · 1 industry

Detailed explanation

There's no universally optimal database. Relational databases (PostgreSQL, MySQL) offer ACID transactions, complex joins, and rigid schemas, ideal when data consistency is critical (payments, inventory). Document databases (MongoDB) allow flexible schemas and nested data, useful when data structure varies a lot between records. Key-value stores (Redis) are extremely fast for key-based access, perfect for caching and sessions. Columnar databases (Cassandra) scale horizontally natively and are optimized for massive writes and time-range queries. Graph databases (Neo4j) naturally model complex relationships between entities. Using PostgreSQL for everything because it's familiar can work at first, but reaching millions of records with the wrong data model may require a complete migration.

Practical example

An event analytics system uses Cassandra to store millions of events per day (optimized for writes) and Redis for the real-time counters shown on the dashboard (optimized for fast reads), while user data stays in PostgreSQL.

H15 Architecture Primary

Adopt microservices architecture over monoliths

Split the application into small, independent services, each with its own database and well-defined business responsibility, deployed and scaled autonomously.

Consensus index 17.6%
Mentioned in 3 of 17 sources · 1 academic · 2 industry

Detailed explanation

Microservices let you scale individual components based on their specific needs, instead of scaling the whole system. A high-demand search service might have 20 instances while the reporting service has 2. Each team can develop, deploy, and scale its service independently without coordinating with other teams. However, microservices introduce significant operational complexity: network communication between services (with its latency and possibility of failure), managing multiple databases, distributed tracing, and greater infrastructure overhead. The literature agrees on an important warning: starting a new project with microservices before knowing the domain's natural boundaries usually results in a poorly divided architecture that's harder to maintain than a well-structured monolith. The recommendation is to start with a modular monolith and extract services once bottlenecks become evident.

Practical example

Amazon started as a monolith in the 1990s. It migrated to microservices during the 2000s when growth made it impossible for hundreds of teams to work on the same codebase without blocking each other.

H16 CI/CD & Deployment Primary

Use containers for deployment consistency

Package the application and all its dependencies into containers (Docker) that guarantee the same artifact behaves identically in development, testing, and production, and that can be deployed and scaled in seconds.

Consensus index 17.6%
Mentioned in 3 of 17 sources · 2 academic · 1 industry

Detailed explanation

Containers eliminate the 'works on my machine' class of problems. By packaging code together with its runtime, OS dependencies, and configuration into an immutable image, you guarantee that what's tested is exactly what's deployed. For scalability, containers are fundamental because they make each service instance identical and interchangeable: the orchestrator (Kubernetes, ECS) can spin up new instances in seconds by copying the image, with no installation or configuration time. They also make horizontal scaling easier because each container is self-contained and requires no additional configuration on startup. Image immutability also improves security and auditability: you always know exactly what's running in production.

Practical example

A team spins up an environment of 10 instances of the same service in 45 seconds using Docker and Kubernetes. Each instance is identical. When a bug is found, rolling back to the previous version takes 30 seconds: only the image tag changes.

S01 Horizontal/Vertical Scaling Secondary

Implement demand-based autoscaling

Configure rules that automatically increase or decrease the number of running instances based on real-time load metrics, without manual intervention.

Consensus index 11.8%

Explanation

Autoscaling combines continuous monitoring (H13) with horizontal scaling (H10) automatically. Thresholds are defined: if CPU exceeds 70% for more than 5 minutes, add 2 instances; if it drops below 30% for 10 minutes, remove 1. This optimizes costs (you don't pay for idle capacity) and ensures availability during unexpected spikes.

S02 Database Secondary

Apply database sharding

Horizontally partition a database's data across multiple independent servers, where each server holds a subset of the data based on some partition key.

Consensus index 11.8%

Explanation

When a database exceeds the capacity of a single server, sharding distributes data across several. For example, users with ID 1-1M on shard 1, ID 1M-2M on shard 2. This distributes both storage and write load. The complexity lies in queries that need data from multiple shards, which must be aggregated at the application level.

S03 API Design Secondary

Adopt an API-first design approach

Design and document the API before implementing business logic, treating the interface as the service's primary contract.

Consensus index 11.8%

Explanation

API-first ensures services expose well-defined interfaces from the start, making decoupling between teams and services easier. Documentation (OpenAPI/Swagger) becomes the source of truth. This reduces implicit dependencies and allows multiple teams to develop in parallel against the same specification.

S04 API Design Secondary

Use an API gateway as a single entry point

Centralize all incoming requests through a single point that handles authentication, authorization, rate limiting, logging, and routing to internal services.

Consensus index 11.8%

Explanation

The API gateway prevents each microservice from having to implement authentication, rate limiting, and logging independently. It centralizes these cross-cutting concerns, reduces the attack surface by not exposing internal services directly, and allows routing changes without modifying clients.

S05 API Design Secondary

Apply rate limiting on APIs

Limit the number of requests a client or user can make within a given time period, protecting the system from abuse, denial-of-service attacks, and misbehaving clients.

Consensus index 11.8%

Explanation

Without rate limiting, a single misconfigured client can make thousands of requests per second, overwhelming system resources and degrading the experience for all users. Rate limiting can be applied by IP, by API key, by authenticated user, or by specific route. Legitimate clients rarely exceed reasonable limits.

S06 Fault Tolerance Secondary

Use multi-availability-zone replication

Distribute service instances across multiple availability zones or geographic regions to ensure an infrastructure failure in one zone doesn't interrupt the entire service.

Consensus index 11.8%

Explanation

Cloud providers divide their infrastructure into availability zones (independent data centers with separate power, network, and cooling). Deploying across multiple zones ensures that a power or network failure in one zone doesn't affect instances in others. It's the foundation of high availability in cloud environments.

S07 Fault Tolerance Secondary

Apply circuit breakers to prevent cascading failures

Implement the circuit breaker pattern, which detects when a dependent service is failing and temporarily stops calling it, returning a fallback response instead of waiting indefinitely for timeouts.

Consensus index 11.8%

Explanation

Without circuit breakers, if service A calls service B and B is down, A waits for the timeout (several seconds) on every request. This exhausts A's threads, which then start failing too, cascading the failure. The circuit breaker detects the error rate and opens the circuit: instead of calling B, it immediately returns a default response. It periodically tests whether B has recovered to close the circuit again.

S08 Fault Tolerance Secondary

Design idempotent operations

Design operations so that executing them multiple times with the same parameters produces the same result as executing them once, enabling safe retries after network failures.

Consensus index 5.9%

Explanation

In distributed systems, networks fail and timeouts happen. When a client doesn't get a response, it doesn't know whether the operation ran or not. If the operation is idempotent, it can be safely retried. Example: instead of POST /orders (which creates an order every time), use PUT /orders/{idempotency-key}, which creates the order if it doesn't exist or returns the existing order if it was already processed.

S09 Architecture Secondary

Adopt a multi-tier architecture with separated layers

Separate the application into physically distinct layers: presentation (web server), business logic (application server), and data (database), each independently scalable.

Consensus index 5.9%

Explanation

Separating into tiers lets you scale each layer according to its needs: more web servers to handle more HTTP connections, more application servers for more logic processing, and more database servers for more data. It also improves security by limiting which layer has access to which resources.

S10 Database Secondary

Use connection pooling for the database

Maintain a set of open connections to the database that are reused across requests, instead of opening and closing a new connection on every request.

Consensus index 5.9%

Explanation

Establishing a database connection has a non-trivial cost: TCP handshake, authentication, parameter negotiation. With thousands of requests per second, that overhead adds up. The connection pool keeps N connections permanently open and lends them out to requests that need them. When the request finishes, it returns the connection to the pool instead of closing it.

S11 Database Secondary

Implement CQRS to separate reads from writes

Use separate models and data paths for read operations (queries) and write operations (commands), optimizing each for its specific access patterns.

Consensus index 11.8%

Explanation

CQRS (Command Query Responsibility Segregation) recognizes that reading and writing data have very different requirements. Writes need consistency and validation; reads need speed and presentation flexibility. By separating the models, reads can use denormalized views optimized for specific queries, while writes use the correct normalized model.

S12 CI/CD & Deployment Secondary

Implement CI/CD for frequent deployments

Automate the integration, testing, and deployment pipeline so every code change is automatically validated and can reach production in minutes with minimal risk.

Consensus index 5.9%

Explanation

CI/CD isn't just convenience: it's an organizational scalability practice. When deploys are frequent and small, each change has a limited impact and errors are easy to identify and revert. Large, infrequent deploys accumulate risk and make rollbacks painful.

S13 Frontend/Client Secondary

Apply lazy loading for non-essential resources

Delay loading resources (images, scripts, components) that aren't needed for the initial page render, downloading them only when the user needs them.

Consensus index 11.8%

Explanation

A page's initial load time determines whether the user stays or leaves. Loading everything upfront (off-screen images, components for features the user may never use) unnecessarily penalizes that time. Lazy loading prioritizes what's visible and defers the rest.

S14 Horizontal/Vertical Scaling Secondary

Use container orchestration for autoscaling

Use platforms like Kubernetes or Amazon ECS to automatically manage container lifecycles, including scaling, self-healing after failures, and load distribution.

Consensus index 11.8%

Explanation

Container orchestration automates what would be impossible to do manually at scale: detecting that an instance failed and spinning up another in seconds, distributing instances across nodes based on available resources, scaling based on load metrics, and managing updates with no downtime. Kubernetes has become the de facto standard for this.

S15 Monitoring & Observability Secondary

Base scaling decisions on real metrics

Make architecture and scaling decisions based on measured data about the system's actual behavior, not on assumptions or technology trends.

Consensus index 5.9%

Explanation

Premature optimization is costly in time and complexity. Adopting microservices, sharding, or caching without evidence they're needed introduces complexity without benefit. The right approach is to measure first, identify the real bottleneck with data, and then apply the specific solution for that problem.

S16 Architecture Secondary

Use event-based messaging between services

Communicate between services by publishing and consuming events through a message broker (Kafka, RabbitMQ), instead of direct synchronous calls between services.

Consensus index 5.9%

Explanation

Synchronous communication creates temporal coupling: service A can't complete its work without service B responding. If B is slow or down, A suffers. Event-based messaging decouples this dependency: A publishes an 'order created' event and continues; B, C, and D consume that event whenever they can. This improves resilience and lets each service scale independently.

S17 Fault Tolerance Secondary

Apply chaos engineering to validate resilience

Deliberately inject failures into the system under controlled conditions to discover weaknesses before they occur unplanned in production.

Consensus index 11.8%

Explanation

Chaos engineering, popularized by Netflix with Chaos Monkey, starts from the premise that the only way to know how a system fails is to make it fail in a controlled way. Instances are randomly shut down, artificial latency is introduced, network connections are cut. Problems discovered this way have planned solutions; those discovered during a real incident come with time pressure.

S18 Database Secondary

Avoid over-fetching data in queries

Design queries to retrieve only the data that's needed, avoiding SELECT * or fetching thousands of records when you only need to know if one exists.

Consensus index 5.9%

Explanation

Every byte transferred between the database and the application consumes CPU, memory, and network bandwidth. SELECT * on a table with 50 columns when only 3 are needed is waste multiplied by every request. Using EXISTS instead of COUNT(*) to check existence, LIMIT to paginate results, and selecting only the needed columns are practices that reduce load proportionally to volume.

S19 API Design Secondary

Implement pagination instead of returning all records

Design APIs to return data in limited-size pages, with mechanisms to navigate between pages, instead of returning all records in a single response.

Consensus index 5.9%

Explanation

An API that returns all of a table's records with no limit is a time bomb. With 100 records it works fine. With 100,000 records, the server burns memory serializing all of them, the network transfers megabytes, and the client chokes processing the response. Offset-based pagination (LIMIT/OFFSET) or cursor-based pagination (WHERE id > last_seen_id) keeps responses bounded regardless of total volume.

S20 Monitoring & Observability Secondary

Define SLA, SLO, and SLI for the system

Formally establish service level agreements (SLA), service level objectives (SLO), and the indicators that measure them (SLI) to have objective criteria for when the system is performing well or poorly.

Consensus index 5.9%

Explanation

Without formal definitions of 'what's acceptable,' it's impossible to know when there's a problem that deserves attention versus normal variation. An SLO like 'P99 latency must be under 500ms' turns monitoring into something actionable. The SLI is the measured metric (actual P99 latency). The SLA is the commitment to the customer around that objective. Together they create a data-driven reliability culture.