1. System Design Foundations and Quality AttributesIntroduction and ContextSystem design is the discipline of deciding how software, infrastructure, data, people, and operational practices should be organised so that a system fulfils its purpose under expected conditions. Programming usually concentrates on making an individual component correct. System design extends that concern to interactions, scale, failure, security, evolution, and cost. A web application that works correctly for ten users may fail when serving ten million; a service that responds quickly may nevertheless be unsuitable if it loses transactions; and a highly available platform may be economically unjustified for a low-risk internal tool. For a postgraduate student of full stack development, system design provides the bridge between application development and architecture. It explains why choices such as database structure, caching, service boundaries, deployment topology, communication protocols, and observability must be considered together. The central design task is not to find a universally perfect architecture. It is to construct a defensible solution for a particular set of requirements and constraints, while making trade-offs explicit. A useful system-design conversation begins with four questions: What problem does the system solve? Who or what interacts with it? What behaviour is required? Under what quality, operational, legal, and economic constraints must it operate? These questions establish the foundation for the analysis in this chapter. Learning ObjectivesAfter completing this chapter, a student should be able to: - define a system, subsystem, component, interface, boundary, dependency, and constraint;
- distinguish functional requirements from non-functional requirements and express quality attributes measurably;
- explain scalability, availability, reliability, latency, throughput, consistency, maintainability, security, and cost;
- use basic metrics and frameworks to analyse architectural alternatives;
- identify tensions among quality attributes and justify trade-offs;
- apply system-design reasoning to a realistic web-platform scenario; and
- recognise professional, ethical, governance, and operational responsibilities in architecture decisions.
Seeing a System as a Set of InteractionsA system is an organised set of elements that interact to achieve one or more purposes. In a web application, the elements may include browsers, mobile clients, application servers, databases, queues, identity providers, monitoring tools, operators, and external partners. The system boundary determines what is included in the design and what is treated as an external dependency. A component is a relatively coherent part of a system with a defined responsibility. It may be a class, module, service, database, message broker, or infrastructure subsystem. Components are not defined only by their implementation technology. A component is valuable architecturally because its responsibility, ownership, data, and interaction with other components can be understood. An interface is an agreed means through which components communicate. An interface may be an HTTP API, event schema, function signature, database contract, user interface, or operational procedure. Interfaces reduce the need for one component to know the internal details of another. A well-designed interface specifies inputs, outputs, errors, security expectations, versioning rules, and relevant performance assumptions. Dependencies arise when one component relies on another for data, computation, availability, or timing. Dependencies may be direct, such as an application calling a database, or indirect, such as a reporting service depending on the correctness of events emitted by an order service. Dependency analysis is important because a system’s effective reliability is often limited by its most critical dependencies. Constraints are conditions that restrict the design space. They include budget, deadline, staffing, regulatory obligations, existing technology, data-residency rules, organisational skills, and compatibility with legacy systems. Constraints are not necessarily defects. A design that ignores them is incomplete, even if it is technically elegant. Functional and Non-Functional RequirementsFunctional requirements describe what a system does. Examples include registering a customer, calculating a shipping charge, accepting a payment request, searching a catalogue, or allowing an administrator to revoke access. They are often represented through use cases, user stories, workflows, domain rules, and API specifications. Non-functional requirements describe how well, under what conditions, or with what properties the system performs its functions. They include response time, availability, security, recoverability, maintainability, accessibility, capacity, and cost. The term “non-functional” can be misleading: these requirements are not secondary. They determine whether the functions are usable and trustworthy. A weak requirement says, “The system must be fast.” A stronger requirement says, “For 95 percent of catalogue requests, the response must be returned within 300 milliseconds at 2,000 requests per second during normal operation.” The second statement identifies a metric, a threshold, a workload, and a condition. It can be tested and used to guide design. Requirements should also identify scope and priority. For example, a payment system may prioritise correctness and auditability over extremely low latency, whereas an online game may prioritise responsiveness and graceful degradation. Quality attributes are meaningful only in relation to a workload, user expectation, business risk, and operating environment. Quality Attributes and Their MeasuresQuality attributes are observable properties of a system that influence stakeholder value. They should be analysed as measurable objectives rather than vague adjectives. ScalabilityScalability is the ability of a system to accommodate growth in workload while maintaining acceptable performance and cost. Workload may grow in users, requests per second, stored data, geographical regions, or background jobs. Vertical scaling increases the capacity of one machine by adding CPU, memory, storage, or network capability. It is often simple but eventually limited by hardware ceilings and may create a large failure domain. Horizontal scaling adds instances and distributes work among them. It can provide greater capacity and resilience, but requires stateless processing, load distribution, data coordination, deployment automation, and careful handling of shared state. A system may scale in one dimension and fail in another. A web tier may scale horizontally while a single database becomes a bottleneck. A queue may absorb bursts but increase processing delay. Effective scalability therefore requires identifying bottlenecks, measuring capacity, and testing realistic workload patterns. Capacity planning commonly uses a target utilisation level, expected growth, peak-to-average ratios, and a safety margin. Availability and ReliabilityAvailability is the proportion of time a service is operational and accessible. It is commonly expressed as a percentage or as downtime over a period. A service with an availability target of 99.9 percent permits substantially more downtime than one targeting 99.99 percent. The extra “nine” may require redundant infrastructure, automated failover, stronger operational practices, and higher expenditure. Reliability is the probability that a system performs correctly for a specified period and operating condition. A service can be available but unreliable: it may respond to every request while returning incorrect results. Conversely, a system may be reliable for individual operations but unavailable during infrastructure failure. Reliability engineering addresses failure prevention, detection, containment, recovery, and learning. Redundancy, health checks, replication, backups, retry policies, circuit breakers, and disaster-recovery procedures can improve resilience. However, redundancy introduces complexity and can create correlated failures if all replicas share the same region, software defect, credentials, or configuration. Latency and ThroughputLatency is the elapsed time between an operation being initiated and its result being available. It may be measured at the client, application, database, or network layer. Average latency is insufficient for many systems because a small number of slow requests can seriously affect user experience. Percentiles such as p95, p99, and p99.9 describe the experience of the slower portion of requests. Throughput is the amount of work completed per unit of time, such as requests per second, orders per minute, or records processed per hour. High throughput does not necessarily imply low latency. A batch processor may achieve excellent throughput while individual items wait several minutes. Conversely, a low-latency system may process only a small number of requests. Latency budgets allocate an overall response-time target among network calls, application processing, storage, and external services. As synchronous dependencies accumulate, tail latency tends to increase. Caching, batching, asynchronous processing, data locality, and reducing unnecessary calls are common techniques, but each introduces trade-offs in freshness, complexity, or consistency. Consistency and Availability in Distributed SystemsConsistency describes the relationship between replicas or observers of data. Strong consistency aims to make a successful write immediately visible according to a defined ordering. Eventual consistency permits temporary differences, provided that replicas converge when updates stop. Other models include read-your-writes consistency, monotonic reads, and causal consistency. Consistency is not simply “good” or “bad.” A social-media reaction count may tolerate temporary divergence, while an account balance or inventory reservation may require stronger guarantees. The correct choice depends on business rules and the consequences of stale or conflicting data. In a distributed system, communication can be delayed or fail. A design that must continue operating during network partitions may need to sacrifice immediate consistency, reject some operations, or use conflict-resolution mechanisms. The practical lesson is to define the required consistency for each operation rather than assigning one global label to the entire platform. Maintainability and EvolvabilityMaintainability is the ease with which a system can be understood, corrected, tested, operated, and changed. Evolvability emphasises the ability to add capabilities without disproportionate risk or effort. Clear boundaries, cohesive modules, automated tests, documentation, observability, simple deployment, and consistent coding standards support both qualities. An architecture may be operationally efficient but difficult to change because business rules are scattered across services. Alternatively, a modular design may be easy to evolve but impose additional runtime communication. Technical debt is not merely old code; it is the future cost created by shortcuts, unclear decisions, obsolete dependencies, inadequate tests, or missing operational knowledge. Security and PrivacySecurity protects confidentiality, integrity, and availability. Authentication establishes identity; authorisation determines permitted actions; accounting and auditing record relevant activity. Secure design also addresses input validation, secrets management, encryption in transit and at rest, dependency vulnerabilities, rate limiting, abuse prevention, and secure failure behaviour. Privacy concerns the lawful and responsible collection, use, retention, sharing, and deletion of personal data. Data minimisation, purpose limitation, access controls, retention schedules, consent where applicable, and traceable data flows are architectural concerns, not merely compliance paperwork. A technically available feature may be inappropriate if it exposes sensitive information or enables discriminatory outcomes. CostCost includes infrastructure, licences, network transfer, storage, support, engineering time, operations, incidents, compliance, and opportunity cost. A design with the lowest hosting bill may produce higher engineering and outage costs. Total cost of ownership should therefore be assessed across the system’s expected life. Cost optimisation is not identical to cost reduction. It seeks an appropriate relationship between expenditure and value. For example, keeping multiple replicas may be justified for a payment service but unnecessary for a temporary analytics environment. Cost should be visible through budgets, usage monitoring, unit economics, and architectural decision records. Frameworks for Architectural ReasoningA practical design process begins by identifying stakeholders and business outcomes. Product owners may care about feature delivery; users about responsiveness and trust; operations teams about recoverability; regulators about evidence and data handling; and finance teams about predictable expenditure. Their concerns should be translated into measurable requirements. Workload modelling then describes expected and exceptional use. Important variables include concurrent users, request rate, payload size, read-to-write ratio, data growth, peak traffic, geographic distribution, and dependency behaviour. Without a workload model, claims about scalability or performance are speculative. The next step is decomposition. A context diagram identifies external actors and systems. A container or subsystem view identifies major runtime responsibilities and data stores. A component view explains internal collaboration where necessary. The goal is not to create diagrams for their own sake, but to expose boundaries, dependencies, trust zones, and likely bottlenecks. Architectural decisions should be evaluated against scenarios. A scenario states an stimulus, operating condition, expected response, and measurable outcome. For example: “If one application instance fails during normal traffic, requests should be redistributed without user-visible interruption and error rates should remain below a specified threshold.” Scenario-based analysis prevents vague claims such as “the architecture is resilient.” A decision matrix can compare alternatives using weighted criteria such as latency, availability, development effort, operational complexity, security risk, and cost. Weights should reflect stakeholder priorities. The result is not mathematical truth; it is a transparent record of assumptions. Architecture Decision Records are useful for documenting the decision, context, alternatives, consequences, and conditions that might justify revisiting it. The process should include validation through prototypes, load tests, failure tests, security review, and operational rehearsal. A design is a hypothesis about system behaviour. Evidence should replace intuition wherever feasible. Trade-offs Rather Than Universal Best PracticesSystem design is fundamentally the management of trade-offs. Replication can improve availability and read capacity but creates consistency and operational costs. Caching reduces latency and database load but introduces invalidation problems and possible staleness. Microservices can permit independent deployment and team ownership but increase network calls, observability demands, and distributed failure modes. A monolith can be a strong choice when a domain is small, a team is compact, and transaction boundaries are closely related. Synchronous communication is easy to understand and suitable when an immediate result is required. Asynchronous messaging decouples producers and consumers and absorbs bursts, but introduces delay, duplicate delivery, ordering questions, and more difficult debugging. Retries improve success during transient faults but may amplify load or duplicate non-idempotent operations. Timeouts, backoff, idempotency keys, and dead-letter handling are therefore essential companions to retry logic. A design should also distinguish hard constraints from preferences. A legal data-residency requirement may be non-negotiable; a particular programming language may be a preference. Explicit prioritisation prevents teams from attempting to maximise every attribute simultaneously, which is usually impossible and economically wasteful. Applied Case: Designing a National Appointment PlatformBackgroundThe following is an illustrative case. A public health organisation plans an online platform through which citizens can search for appointments, reserve a slot, receive notifications, and cancel or reschedule. Clinics use a separate interface to publish availability. The service is expected to experience concentrated demand when new appointment batches are released. Situation and ProblemThe initial prototype uses a single application server and relational database. It performs acceptably during ordinary traffic but becomes slow during appointment releases. More seriously, two users can occasionally reserve the same slot. The organisation requires auditability, protection of personal information, high availability during release periods, and a cost that can be justified for public funding. AnalysisThe primary functional requirements are searching availability, creating a reservation, cancelling, notifying users, and allowing authorised clinic staff to manage slots. Critical quality requirements differ by operation. Search can tolerate slightly stale results if the reservation operation verifies availability authoritatively. Reservation requires strong protection against double booking and a durable audit record. Notification can be asynchronous because a booking need not wait for an email or text message to be delivered. The workload is read-heavy during searches but write-sensitive during reservations. Traffic is bursty rather than uniform. A single database and application instance create availability risks and capacity limits. Caching search results can reduce read load, but cached availability must never be treated as the final authority for booking. ApproachThe proposed design uses multiple stateless application instances behind a load balancer. A relational database remains the system of record because reservation correctness and transactional constraints are central. A database transaction, unique constraint, or equivalent concurrency-control mechanism ensures that a slot cannot be successfully assigned twice. The reservation request includes an idempotency key so that a client retry does not create a second booking. Search results may be cached for a short, explicitly accepted period. The booking service rechecks the slot in the database and returns a clear outcome if it has already been taken. A queue receives notification events after a successful reservation. Workers process these events with retry and dead-letter handling. The audit trail records the actor, action, time, relevant identifiers, and outcome, while sensitive data is restricted and retained according to policy. Health checks remove failed application instances from service. Database backups are tested through restoration exercises rather than merely configured. Metrics include reservation success rate, double-booking violations, p95 and p99 latency, queue delay, database utilisation, error rate, and cost per reservation. Load tests reproduce the appointment-release burst, while failure tests examine instance loss, queue delay, and database failover. OutcomeThe architecture separates functions according to their quality needs: cached search improves responsiveness, transactional booking protects correctness, and asynchronous notification prevents messaging providers from determining booking latency. It does not attempt to make every component strongly consistent or infinitely scalable. Instead, it places strong guarantees at the business boundary where failure is most harmful and accepts controlled staleness where the risk is lower. Learning PointsThe case demonstrates that quality attributes are operation-specific. It also shows why a scalable web tier cannot compensate for an unexamined data bottleneck, why retries require idempotency, and why availability claims must include dependencies, recovery procedures, and evidence. Finally, privacy, accessibility, auditability, and public accountability are part of system design rather than post-deployment additions. Common Errors and Professional ResponsibilitiesA frequent mistake is choosing technologies before defining requirements. Another is measuring only average latency, ignoring tail behaviour and peak workload. Teams also overuse microservices, assume that a cache is automatically beneficial, treat backups as proof of recoverability, and count replicas without examining correlated failure. Poorly designed health checks can declare a system healthy while its dependencies are unusable. Unbounded retries, missing timeouts, and non-idempotent operations commonly turn temporary faults into cascading failures. Architects and developers have a professional duty to communicate uncertainty and consequences. Security controls should not be weakened merely to meet a deadline without documenting the risk and obtaining appropriate approval. Personal data should not be collected because it might become useful later. Accessibility, fairness, and the interests of less powerful users should be considered during requirements and testing. Governance requires traceable decisions, controlled changes, incident learning, and evidence that stated objectives are being met. Current DirectionsModern architectures increasingly use managed cloud services, containers, serverless execution, platform engineering, and infrastructure as code. These approaches can improve delivery speed and elasticity but do not remove design responsibility; they shift some operational work to providers and introduce dependency, portability, and cost considerations. Observability is developing from isolated logs and dashboards toward correlated traces, structured events, service-level indicators, and service-level objectives. Automated anomaly detection and machine-learning assistants can help identify capacity patterns, classify incidents, or suggest code and configuration changes. Such tools require human review because inaccurate recommendations, sensitive telemetry, opaque decisions, and automated changes can create security or reliability risks. Green software engineering is also becoming relevant. Efficient algorithms, right-sized infrastructure, workload scheduling, storage lifecycle policies, and reduced data transfer can lower both cost and environmental impact. The appropriate objective is not an abstract pursuit of maximal performance, but efficient delivery of the required user and organisational value. Best-Practice GuidanceA sound system-design practice should: 1. begin with users, business outcomes, workload, and constraints; 2. state quality requirements with measurable thresholds and operating conditions; 3. keep component responsibilities and interfaces explicit; 4. identify critical dependencies and single points of failure; 5. choose consistency, communication, and storage models per business operation; 6. design for failure using timeouts, bounded retries, idempotency, graceful degradation, and tested recovery; 7. measure percentiles, saturation, errors, capacity, and cost rather than relying on averages; 8. automate testing, deployment, security checks, and infrastructure management where appropriate; 9. document important decisions and revisit them when assumptions change; and 10. treat privacy, accessibility, auditability, and operational learning as design requirements. Chapter SummarySystem design organises components, interfaces, data, infrastructure, and people to satisfy a purpose under explicit constraints. Functional requirements describe system behaviour, while non-functional requirements express measurable qualities such as performance, availability, security, and maintainability. Scalability concerns growth; availability concerns accessibility; reliability concerns correct operation; latency and throughput describe time and volume; consistency defines the relationship among data views; and cost includes the full life-cycle burden of a design. Architectural reasoning uses stakeholder analysis, workload modelling, decomposition, scenarios, decision matrices, prototypes, and testing. No architecture maximises every quality simultaneously. Replication, caching, asynchronous communication, service decomposition, and strong consistency each create benefits and costs. The illustrative appointment platform showed how guarantees should be concentrated on high-risk operations while less critical work can be cached or processed asynchronously. Effective system design is therefore evidence-based trade-off management supported by security, governance, observability, and continuous operational learning. Key TermsSystem: An organised set of interacting elements that achieves a purpose. Component: A coherent system element with a defined responsibility. Interface: An agreed mechanism and contract for interaction between components. System boundary: The distinction between elements included in a system and external actors or dependencies. Constraint: A condition that limits possible design choices. Functional requirement: A statement of behaviour or capability the system must provide. Non-functional requirement: A measurable property or condition governing how the system operates. Quality attribute: An observable system property that affects stakeholder value. Scalability: The ability to accommodate increased workload while maintaining acceptable objectives. Availability: The proportion of time a service is accessible and operational. Reliability: The probability of correct operation under specified conditions for a specified period. Latency: The elapsed time between initiating an operation and receiving its result. Throughput: The amount of work completed per unit of time. Consistency: The rules governing visibility and ordering of data among observers or replicas. Maintainability: The ease of understanding, correcting, operating, testing, and changing a system. Idempotency: The property that repeating an operation produces the same intended effect as performing it once. Observability: The ability to infer internal system behaviour from outputs such as logs, metrics, and traces. Technical debt: Future cost or reduced adaptability resulting from expedient or deficient technical decisions. Architecture Decision Record: A documented statement of an architectural decision, its context, alternatives, and consequences. Review QuestionsShort Answer Questions1. Distinguish a component from an interface using a web application example. 2. Why should non-functional requirements be expressed with metrics and operating conditions? 3. Differentiate availability from reliability. 4. What is the difference between latency and throughput? 5. Why is idempotency important when retrying requests? Long Answer Questions1. Explain the major quality attributes discussed in this chapter and show how they can conflict in a distributed web system. 2. Describe a systematic process for moving from stakeholder needs to an evidence-based architectural decision. 3. Compare vertical and horizontal scaling, including their benefits, limitations, and operational implications. 4. Explain how consistency should be selected according to business operations rather than applied uniformly to an entire system. 5. Discuss the professional, privacy, security, and governance responsibilities involved in system design. Analytical / Application Questions1. A ticketing service has low average latency but severe delays during peak sales and occasional duplicate bookings. Analyse likely causes and propose measurable requirements and design responses. 2. A team proposes replacing a modular monolith with fifteen microservices to improve scalability. Using the chapter’s trade-off framework, identify the evidence required before accepting or rejecting the proposal. 3. Design a quality-attribute strategy for an online learning platform that must support video access, assignment submission, grading, and notifications. Specify where strong consistency, caching, asynchronous processing, and graceful degradation should be used. 22. Multiple Choice Questions with AnswersQuestion 1Which statement best distinguishes a functional requirement from a non-functional requirement? A. A functional requirement describes what the system does, while a non-functional requirement describes a measurable quality or operating condition. B. A functional requirement applies only to infrastructure, while a non-functional requirement applies only to users. C. A functional requirement is optional, while a non-functional requirement is mandatory. D. A functional requirement describes cost, while a non-functional requirement describes source code. Correct Answer: A. A functional requirement describes what the system does, while a non-functional requirement describes a measurable quality or operating condition. Question 2A system must handle increasing traffic while maintaining acceptable response time and cost. Which quality attribute is being prioritised? A. Reliability B. Scalability C. Consistency D. Auditability Correct Answer: B. Scalability Question 3Why are latency percentiles such as p95 often more useful than average latency? A. They eliminate the need to measure throughput. B. They show the experience of slower requests that averages can hide. C. They guarantee that every request meets the target. D. They measure only database performance. Correct Answer: B. They show the experience of slower requests that averages can hide. Question 4A booking request may be retried after a network timeout. Which design feature most directly prevents the retry from creating a duplicate booking? A. A larger cache B. An idempotency key C. A faster user interface D. A second load balancer Correct Answer: B. An idempotency key Question 5Which situation best illustrates availability without reliability? A. The service is unreachable during a network outage. B. The service responds to every request but sometimes returns incorrect account balances. C. The service rejects requests during planned maintenance. D. The service processes work asynchronously. Correct Answer: B. The service responds to every request but sometimes returns incorrect account balances. Question 6In the appointment-platform case, why can search results be cached while booking must recheck the database? A. Search is always more important than booking. B. Cached data is suitable for discovery, but booking requires authoritative protection against double reservation. C. Databases cannot process read requests. D. Caching automatically provides strong consistency. Correct Answer: B. Cached data is suitable for discovery, but booking requires authoritative protection against double reservation. Question 7Which architectural choice most directly absorbs a burst of work while decoupling the producer from a slower consumer? A. Asynchronous messaging through a queue B. Increasing the font size of the user interface C. Removing all timeouts D. Using only vertical scaling Correct Answer: A. Asynchronous messaging through a queue Question 8What is a major risk of unbounded retries in a distributed system? A. They always reduce throughput predictably. B. They can amplify load and cause cascading failures. C. They guarantee data consistency. D. They remove the need for monitoring. Correct Answer: B. They can amplify load and cause cascading failures. Question 9Which statement reflects sound system-design reasoning? A. One architecture maximises every quality attribute simultaneously. B. Technology selection should precede requirements analysis. C. Quality decisions should be evaluated against workload, business risk, and constraints. D. A configured backup proves that recovery is possible. Correct Answer: C. Quality decisions should be evaluated against workload, business risk, and constraints. Question 10A team wants to evaluate two architectures using latency, availability, cost, and operational complexity. Which method best supports a transparent comparison? A. Choosing the newest technology automatically B. A weighted decision matrix supported by documented assumptions C. Selecting the architecture with the most components D. Comparing only average response time Correct Answer: B. A weighted decision matrix supported by documented assumptions
|