Software Engineering

Chapter 4
Software Architecture and System Design

Post Graduate Program in Computer Science Engineering
Software Engineering   •   Post Graduate

4. Software Architecture and System Design

Introduction and Context

Software systems rarely fail because a programmer cannot write an individual function. They fail because the system as a whole is difficult to understand, change, test, operate, secure, or scale. Software architecture addresses this system-level concern. It establishes the major structures of a software system, the responsibilities assigned to those structures, and the relationships through which they collaborate. System design then refines these architectural decisions into components, interfaces, data flows, algorithms, deployment units, and operational mechanisms.

Architecture is therefore more than a collection of technologies. A system built with microservices is not automatically well architected, and a monolithic system is not necessarily poorly designed. Architecture is concerned with the consequences of design decisions: how easily the system can evolve, how it behaves under failure, how it protects information, and how effectively teams can develop and operate it.

This chapter examines abstraction, decomposition, modularity, SOLID principles, UML, architectural styles, design patterns, distributed systems, event-driven systems, microservices, cloud-native design, and quality-attribute trade-offs. It also considers architecture as a decision-making discipline involving technical, organizational, economic, ethical, and governance considerations.

Learning Objectives

After studying this chapter, the learner should be able to:

1. Distinguish software architecture from detailed system design and implementation.

2. Apply abstraction, decomposition, encapsulation, cohesion, and coupling in modular design.

3. Explain and use the SOLID principles appropriately rather than mechanically.

4. Represent systems using relevant UML diagrams and architectural views.

5. Compare layered, client–server, hexagonal, event-driven, microservice, and cloud-native architectures.

6. Select and adapt design patterns to solve recurring design problems.

7. Evaluate trade-offs among quality attributes such as performance, scalability, availability, security, maintainability, and cost.

8. Analyze distributed-system concerns, including consistency, failure, observability, and communication.

9. Make architecture decisions that are technically sound, professionally responsible, and aligned with organizational objectives.

Architecture as a Set of Significant Decisions

A software architecture can be understood as the set of structures needed to reason about a system, together with the architectural decisions governing those structures. Structures may be static, such as modules and deployment nodes, or dynamic, such as interactions among services and events. An architectural decision records not only what was selected but also the context, alternatives considered, consequences, and assumptions.

Architecture differs from implementation detail in degree rather than in absolute kind. The choice of a database technology may be architectural when it constrains availability, transaction semantics, or scaling. The choice of a local variable name is ordinarily an implementation detail. The boundary is determined by the extent to which a decision affects the system's qualities and future evolution.

A useful distinction is between functional requirements and quality attributes. Functional requirements state what the system does—for example, allowing a customer to place an order. Quality attributes describe how it performs or behaves—for example, processing 95 percent of requests within two seconds, preserving confidentiality, or remaining available during the failure of one computing region. Architecture is especially important because quality attributes are strongly shaped by structural decisions.

Architectural reasoning often follows this sequence:

  • identify business capabilities, stakeholders, constraints, and quality goals;
  • define system boundaries and responsibilities;
  • decompose responsibilities into modules or services;
  • define interfaces, data ownership, and interaction mechanisms;
  • select deployment and operational arrangements;
  • evaluate risks, trade-offs, and failure behavior; and
  • document decisions and validate them through prototypes, tests, and review.

This is not a strictly linear process. New information may require revisiting boundaries or replacing an architectural style. Mature architecture work is iterative and evidence-based.

Abstraction, Decomposition, and Modularity

Abstraction focuses attention on essential properties while hiding irrelevant detail. An interface such as `PaymentGateway` expresses the capability required by an application without exposing whether payment is performed through a bank API, a card network, or a simulated test component. Good abstraction reduces cognitive load and protects clients from unnecessary change. Poor abstraction either leaks implementation details or becomes so general that it communicates no useful contract.

Decomposition divides a complex system into smaller parts. The most valuable decomposition is not merely one that produces many components; it assigns coherent responsibilities and establishes boundaries that limit the effect of change. A module should ideally have high cohesion—its elements should contribute to a common purpose—and low coupling—its dependence on other modules should be limited, explicit, and stable.

Encapsulation protects internal decisions behind a public boundary. For example, an inventory component may expose `reserve(item, quantity)` while hiding allocation algorithms, storage schemas, and locking mechanisms. Encapsulation permits implementation change without requiring changes throughout the system.

Several decomposition criteria are commonly used:

  • Business capability: customer management, billing, shipment, or fraud analysis.
  • Domain concept: order, account, policy, or product.
  • Technical responsibility: persistence, messaging, authentication, or presentation.
  • Change volatility: elements likely to change together are placed together.
  • Security or compliance boundary: sensitive data and privileged operations are isolated.
  • Deployment or scaling need: independently scalable or independently releasable components may require separate units.

No single criterion is universally correct. Decomposition by technical layers can provide consistency, whereas decomposition by business capability may improve ownership and evolutionary independence. The appropriate choice depends on the system's goals and constraints.

A common design error is premature fragmentation. Splitting a small and stable application into numerous services introduces network calls, deployment complexity, distributed transactions, and operational overhead. Modularity can be achieved inside a well-structured monolith. A modular monolith often provides a useful intermediate architecture: modules have explicit interfaces and data ownership, but deployment remains unified. Such a design preserves the option of future extraction without paying distributed-system costs prematurely.

SOLID Principles in Context

The SOLID principles are heuristics for object-oriented and modular design. They should guide judgment, not replace it.

Single Responsibility Principle states that a class or module should have one reason to change. A report generator that formats output, queries a database, sends email, and applies business rules has several reasons to change. Separating these concerns reduces accidental coupling. The principle does not mean that every class must contain one method; it means that responsibilities should be coherent.

Open–Closed Principle proposes that software entities should be open for extension but closed for modification. Stable abstractions can permit new behavior through polymorphism or composition. For example, a pricing engine may accept interchangeable discount policies rather than requiring its central algorithm to be repeatedly edited. Excessive abstraction, however, may make simple changes harder, so the principle should be applied where variation is probable and meaningful.

Liskov Substitution Principle requires that subtypes preserve the behavioral expectations of their base abstractions. If a subtype rejects operations that clients reasonably expect to succeed, the inheritance relationship is misleading. Composition is often preferable when behavior cannot be substituted safely.

Interface Segregation Principle advises that clients should not depend on methods they do not use. Several focused interfaces are generally more robust than one large interface containing unrelated operations. This is particularly important across service boundaries, where broad interfaces create unnecessary coupling.

Dependency Inversion Principle states that high-level policy should not depend directly on low-level details; both should depend on abstractions. Details such as a database adapter or message broker can then be replaced or tested independently. Dependency inversion is implemented through interfaces, dependency injection, ports and adapters, or similar mechanisms.

SOLID principles interact with cohesion, coupling, testability, and changeability. Blind application can result in excessive indirection, excessive classes, and abstractions with no genuine variation. The correct question is not whether a design contains many interfaces, but whether its dependencies reflect stable responsibilities and useful boundaries.

Modeling Systems with UML and Architectural Views

UML is a modeling language rather than a development method. It helps stakeholders communicate structure and behavior when diagrams are kept purposeful and consistent. At postgraduate level, UML should be used selectively to answer design questions rather than to decorate documents.

A use-case diagram identifies actors and system goals. It is useful during scope and stakeholder analysis but does not describe internal implementation. A class diagram shows classes, interfaces, attributes, operations, and relationships. It can express inheritance, aggregation, composition, and dependencies. A sequence diagram emphasizes time-ordered interactions and is valuable for examining request flows, alternative paths, and service collaboration. A state-machine diagram models behavior whose meaning depends on state, such as an order moving from created to paid, dispatched, delivered, or cancelled.

A component diagram represents deployable or replaceable software units and their interfaces. A deployment diagram maps software artifacts to nodes such as containers, virtual machines, mobile devices, or managed cloud services. Activity diagrams represent workflows and parallel behavior.

Architecture is better communicated through multiple views. A logical view explains major responsibilities and relationships; a process view explains runtime interaction and concurrency; a development view explains code organization; a physical or deployment view explains infrastructure; and a scenario view validates the design against important use cases and quality requirements. The well-known “4+1” perspective is one way of organizing these views, but teams may use other approaches, including the C4 model.

Diagrams become harmful when they are too detailed to maintain or when they conceal uncertainty. Every diagram should have a stated purpose, scope, and level of abstraction. Architecture decision records complement diagrams by preserving rationale and trade-offs.

Architectural Styles and Their Appropriate Use

An architectural style provides recurring principles for organizing a system. It is not a rigid recipe.

In a layered architecture, presentation, application or service logic, domain logic, and infrastructure are separated. Dependencies generally point toward lower layers or toward abstractions. Layering supports comprehension, testing, and replacement of infrastructure, but strict layers may introduce pass-through code and performance overhead. A system can also suffer when domain logic leaks into the presentation or persistence layers.

A client–server architecture separates requesters from providers. It remains useful for web applications, database systems, and network services. Its principal concerns include server bottlenecks, connection management, trust boundaries, and failure handling.

Hexagonal architecture, also called ports and adapters, places domain and application policy at the center. Ports define required or provided interfaces, while adapters connect the core to user interfaces, databases, message brokers, or external services. This style supports testability and protects business rules from infrastructure changes.

A pipe-and-filter architecture processes data through independent transformations. It is suitable for compilers, data processing, and analytics pipelines. Filters may be composed and reused, but shared state and error recovery can be difficult.

In an event-driven architecture, producers publish events and consumers react asynchronously. Events represent facts that have occurred, such as `OrderPlaced` or `PaymentConfirmed`. This reduces temporal coupling and supports independent consumers, but introduces challenges involving ordering, duplication, schema evolution, replay, monitoring, and eventual consistency.

A microservice architecture structures an application as independently deployable services organized around business capabilities. Each service should have a clear responsibility, explicit interface, and appropriate data ownership. Benefits may include team autonomy, selective scaling, and independent release. Costs include network latency, distributed failure, operational complexity, difficult end-to-end testing, and the need for mature automation and observability.

Serverless and cloud-native architectures use managed infrastructure, elastic resources, containers, orchestration, automated delivery, and infrastructure as code. Serverless functions can reduce infrastructure administration and suit event-triggered workloads, but execution limits, startup latency, vendor dependence, state management, and cost unpredictability require evaluation. Cloud-native design is not simply moving an old application to virtual machines; it involves designing for automation, elasticity, failure, and observable operation.

Design Patterns as Reusable Design Knowledge

A design pattern identifies a recurring problem, a context, and a proven arrangement of responsibilities. Patterns are not copy-and-paste code. Their value lies in the reasoning they communicate.

The Facade provides a simplified interface to a complex subsystem. The Adapter converts one interface into another expected by a client. The Strategy encapsulates interchangeable algorithms, such as different pricing or routing policies. The Observer supports notification of interested parties, although an in-process observer differs significantly from a durable distributed event mechanism. The Factory Method or Abstract Factory separates object creation from use when construction varies. The Repository presents a domain-oriented interface for persistence, though it should not become a meaningless wrapper over every database operation.

The Circuit Breaker is especially relevant in distributed systems. When a remote dependency repeatedly fails, the circuit opens and rejects or fails fast rather than allowing resource exhaustion through repeated calls. After a controlled period, limited requests test recovery. Timeouts, retries with backoff, bulkheads, idempotency, and fallback behavior often complement it.

Patterns can also become anti-patterns. A Singleton may conceal global state and make testing difficult. Excessive use of factories and facades can create indirection without reducing complexity. Patterns must be justified by forces in the problem, not by fashion.

Quality Attributes and Trade-Off Analysis

Architecture is fundamentally a trade-off activity. Improving one quality attribute may reduce another. Strong consistency can increase latency or reduce availability under partition. Replication can improve availability and read performance but complicate conflict resolution. Encryption improves confidentiality but introduces key-management and processing concerns. Abstraction improves replaceability but may add indirection.

Quality-attribute scenarios make vague requirements testable. A scenario normally specifies a stimulus, an environment, a response, and a measurable response goal. For example: “When a payment request arrives during normal peak load, the system shall authorize 99 percent of valid requests within three seconds.” The scenario identifies what must be measured and allows architecture alternatives to be compared.

Important attributes include:

  • Performance: response time, throughput, resource consumption, and latency distribution.
  • Scalability: ability to handle increased load by adding resources or improving capacity.
  • Availability and resilience: ability to provide service and recover after faults.
  • Security: confidentiality, integrity, authentication, authorization, and accountability.
  • Modifiability: effort and risk required to implement change.
  • Usability and accessibility: effectiveness and inclusiveness of user interaction.
  • Testability and operability: ability to verify, diagnose, deploy, and manage the system.
  • Portability and interoperability: ability to run across environments and interact with other systems.

Architecture evaluation may use scenario-based reviews, prototypes, load tests, threat modeling, failure injection, and cost analysis. A lightweight decision matrix can compare alternatives, but numerical scores should not create false precision. The assumptions behind each score are more valuable than the score itself.

Distributed, Event-Driven, and Data-Centric Design

Distribution changes the nature of failure. A local method call usually either returns or throws an exception within a shared process. A remote call may experience delay, timeout, partial execution, duplicated messages, authentication failure, or an unavailable network. Consequently, every remote interaction needs an explicit timeout and a defined failure policy.

Retries are safe only when the operation is idempotent or protected against duplication. A client retrying a payment request can create two charges unless the operation uses an idempotency key. Distributed transactions may use coordination protocols, but many systems instead use local transactions, durable events, compensating actions, and sagas. A saga coordinates a business process through a sequence of steps; if a later step fails, compensating actions attempt to restore an acceptable business state.

Eventual consistency means that replicas or projections may temporarily disagree but converge if updates are successfully propagated. It can improve availability and responsiveness, but the business process must tolerate stale data. Read models, materialized views, and event sourcing can support specialized queries and auditability. Event sourcing stores state-changing events as the primary record and derives current state by replaying them. It offers traceability and temporal reconstruction but introduces schema evolution, storage, replay, and correction challenges.

Observability is essential in distributed architectures. Logs provide event records, metrics provide numerical signals, and traces connect operations across components. Correlation identifiers allow an operation to be followed through asynchronous and synchronous paths. Observability is not merely a monitoring tool; it is an architectural requirement for diagnosing emergent behavior.

An Illustrative Case: Designing a University Examination Platform

Background

A university plans an online examination platform for question authoring, candidate authentication, timed assessment, answer submission, grading, and result publication. The platform must support ordinary examinations and occasional high-volume assessments involving many simultaneous candidates.

Situation and Problem

An initial proposal recommends twelve microservices, a shared database, synchronous calls between all services, and a single deployment pipeline. The proposal appears modern but does not explain data ownership, failure behavior, or quality targets. During a trial, a slow identity provider causes examination screens to freeze, and repeated answer submissions create inconsistent records.

Analysis

The primary business capabilities are assessment management, candidate eligibility, examination delivery, answer recording, grading, and reporting. Not all capabilities require independent deployment. Examination delivery and answer recording have different scaling and resilience needs from question authoring. The system also has a strict integrity requirement: a candidate's accepted answer must not be silently lost or overwritten.

Quality scenarios are established. During the examination window, a candidate's answer should be acknowledged within a defined response target even if reporting is temporarily unavailable. A repeated submission carrying the same idempotency key must produce one logical answer record. Administrative reporting may be eventually consistent, but the examination record requires stronger consistency.

Approach and Solution

The team chooses a modular architecture initially deployed as two major units: an administrative application and an examination delivery service. Internal modules have explicit interfaces and separate data-access components. The delivery service owns answer records and uses idempotency keys, durable writes, and an append-oriented answer history. A separate reporting projection consumes answer-recorded events and can be rebuilt if necessary.

Authentication tokens are validated locally for routine requests after a controlled login flow, reducing dependence on a remote identity provider during the examination. The platform uses timeouts and circuit breakers for external services. An examination session has a state model that prevents submissions after closure, while server-side time determines the authoritative deadline. Metrics track submission latency, rejected submissions, queue depth, and data-projection lag. Traces and correlation identifiers support incident investigation.

Only after operational evidence demonstrates a need for further independent scaling would the team extract additional services. Deployment is automated, infrastructure is defined as code, and a failure-injection exercise tests behavior when reporting, identity, or messaging components are unavailable.

Outcome

The design avoids premature service fragmentation while preserving clear boundaries and an evolutionary path. Critical answer recording is separated from non-critical reporting, and duplicate submissions are controlled. The architecture does not eliminate all risk, but it makes important risks explicit, measurable, and manageable.

Learning Points

The case demonstrates that architecture should begin with capabilities and quality scenarios rather than fashionable technology. It also illustrates the value of modular monoliths, explicit data ownership, idempotency, asynchronous projections, resilience patterns, and evidence-based evolution.

Professional, Governance, and Ethical Considerations

Architecture decisions allocate power, risk, and cost. A design that maximizes convenience for administrators while making the system inaccessible to users is professionally inadequate. Security and privacy must be considered from the beginning through threat modeling, least privilege, secure defaults, data minimization, retention controls, and auditable access.

Architects should identify regulatory obligations concerning personal data, records, accessibility, financial transactions, or sector-specific controls. Compliance is not equivalent to security; passing a checklist does not guarantee that a system protects people in practice. Sensitive data should not be copied into logs, test environments, or analytics stores without justification and safeguards.

Vendor selection also requires governance. Managed cloud services may improve reliability and reduce operational work, but they can create lock-in, migration difficulty, data-residency concerns, and concentration risk. Architecture records should make such dependencies visible. Teams should distinguish measured evidence from assumptions and should communicate uncertainty to decision makers.

Common Failure Modes and Best Practices

Frequent mistakes include designing from infrastructure technology rather than business responsibility, creating services that share a database without clear ownership, treating synchronous calls as harmless, omitting timeouts, using retries without idempotency, confusing high availability with scalability, and producing diagrams that do not match the deployed system.

Effective practice includes:

  • express important quality attributes as measurable scenarios;
  • keep module and service boundaries aligned with responsibility and data ownership;
  • prefer the simplest architecture that satisfies current and foreseeable needs;
  • document significant decisions, alternatives, assumptions, and consequences;
  • automate builds, tests, security checks, deployment, and infrastructure management;
  • design failure behavior explicitly rather than assuming dependencies are reliable;
  • use observability, operational readiness reviews, and production evidence;
  • validate architecture through prototypes, load tests, threat modeling, and game days; and
  • revisit decisions as requirements, scale, teams, and technologies change.

Current Developments and Emerging Directions

Architecture is increasingly influenced by platform engineering, internal developer platforms, policy as code, software supply-chain security, and automated infrastructure. Teams are adopting standardized deployment paths so that developers can obtain reliable environments without individually managing every infrastructure detail.

AI-assisted software development is changing implementation speed, but it does not remove architectural accountability. Generated code still requires review for security, licensing, data leakage, testability, and alignment with system boundaries. AI-enabled applications also introduce model latency, nondeterminism, prompt or data injection, evaluation difficulty, and governance requirements. Architectures for such systems commonly include retrieval components, model gateways, audit trails, content controls, and human oversight where consequences are significant.

The continuing direction is not toward one universally superior style. Successful systems combine styles selectively: a modular core, asynchronous integration where useful, managed infrastructure where economical, and strong observability and security throughout.

Chapter Summary

Software architecture defines the significant structures, relationships, and decisions that shape a system's behavior and evolution. System design refines those decisions into modules, interfaces, data flows, deployment units, and operational mechanisms. Abstraction, encapsulation, cohesion, low coupling, and purposeful decomposition support modularity. SOLID principles provide useful guidance when applied with judgment.

UML and multiple architectural views help communicate structure, behavior, deployment, and scenarios. Layered, hexagonal, event-driven, microservice, serverless, and cloud-native styles address different forces and impose different costs. Design patterns capture reusable solutions, while distributed systems require explicit treatment of timeouts, retries, idempotency, consistency, failure, and observability.

Architecture is a trade-off discipline. Quality-attribute scenarios, prototypes, testing, threat modeling, and operational evidence help evaluate alternatives. The best architecture is not the most fashionable or distributed one, but the one whose boundaries, decisions, and operational consequences fit the system's goals and constraints.

Key Terms

Abstraction: Representation that emphasizes essential behavior while hiding unnecessary implementation detail.

Architectural decision: A significant choice about system structure, behavior, technology, or quality attributes, including its rationale and consequences.

Cohesion: Degree to which elements within a module contribute to a focused responsibility.

Coupling: Degree of dependency between modules or components.

Encapsulation: Protection of internal state and implementation behind a defined interface.

Modular monolith: A single deployable application composed of explicitly separated internal modules.

SOLID: Five principles guiding maintainable object-oriented and modular design.

Interface segregation: Design principle favoring focused interfaces over broad interfaces containing unrelated operations.

Dependency inversion: Principle that high-level policy and low-level details should depend on abstractions.

UML: Standardized modeling language for representing software structure and behavior.

Architectural style: Recurring organization of components, relationships, and constraints in a system.

Design pattern: Reusable design knowledge describing a recurring problem, context, and solution structure.

Event-driven architecture: Architecture in which components communicate by publishing and consuming events.

Microservice: Independently deployable component organized around a cohesive business capability.

Idempotency: Property that repeating an operation produces the same logical result as performing it once.

Eventual consistency: Model in which distributed replicas may temporarily differ but converge over time.

Saga: Coordination of a distributed business process through steps and compensating actions.

Observability: Ability to understand internal system behavior through logs, metrics, traces, and related signals.

Quality-attribute scenario: Testable statement specifying a stimulus, environment, response, and response measure.

Circuit breaker: Resilience mechanism that limits calls to a failing dependency and permits controlled recovery testing.

Review Questions

Short Answer Questions

1. How does software architecture differ from detailed implementation?

2. Explain the relationship between cohesion and coupling.

3. What problem does the Dependency Inversion Principle address?

4. Why are quality-attribute scenarios useful in architecture evaluation?

5. Define idempotency and state one situation in which it is important.

Long Answer Questions

1. Explain abstraction, decomposition, encapsulation, and modularity, using a software-system example.

2. Discuss the five SOLID principles and evaluate the risks of applying them mechanically.

3. Compare layered, hexagonal, event-driven, and microservice architectures in terms of structure, benefits, and costs.

4. Explain how UML diagrams and architectural views support communication and design validation.

5. Discuss the principal architectural concerns in distributed systems, including consistency, failure, resilience, and observability.

Analytical / Application Questions

1. A small retail application has three developers, modest traffic, and rapidly changing pricing rules. Should it begin as microservices, a modular monolith, or an unstructured monolith? Justify the decision using quality attributes and likely costs.

2. A payment service times out after accepting a request, and the client retries it. Design an interaction using idempotency, timeouts, retries, and failure handling to prevent duplicate charging.

3. Design an architecture for a university examination platform that must preserve answer integrity while allowing reporting and analytics to be temporarily unavailable. Identify modules, data ownership, communication styles, quality scenarios, and trade-offs.

22. Multiple Choice Questions with Answers

Question 1

A team is deciding whether to extract a module from a modular monolith into a separate service. Which consideration most strongly supports extraction?

A. The team wants to use a fashionable technology.

B. The module has a distinct business responsibility and requires independent scaling or deployment.

C. The module contains more than five classes.

D. The application already uses an object-oriented language.

Correct Answer: B. The module has a distinct business responsibility and requires independent scaling or deployment.

Question 2

Which design best demonstrates the Dependency Inversion Principle?

A. A business service directly constructs a concrete database driver.

B. A controller contains SQL statements for every use case.

C. A business policy depends on a persistence abstraction implemented by replaceable adapters.

D. Every class inherits from a single technical base class.

Correct Answer: C. A business policy depends on a persistence abstraction implemented by replaceable adapters.

Question 3

In an event-driven system, what is the principal architectural consequence of making reporting consume answer-recorded events asynchronously?

A. Reporting must always be strongly consistent with the write operation.

B. Reporting can be independently scaled, but temporary projection lag must be accepted and monitored.

C. The system no longer requires data ownership.

D. Network failures become impossible.

Correct Answer: B. Reporting can be independently scaled, but temporary projection lag must be accepted and monitored.

Question 4

A client retries a payment request after receiving a timeout. Which mechanism most directly prevents two logical charges?

A. A larger user interface button

B. An idempotency key recognized by the payment operation

C. A class diagram

D. A second unrelated database

Correct Answer: B. An idempotency key recognized by the payment operation

Question 5

Which UML diagram is most appropriate for examining the time-ordered interaction among a user interface, order service, and payment service?

A. Deployment diagram

B. Sequence diagram

C. Use-case diagram

D. Package diagram

Correct Answer: B. Sequence diagram

Question 6

What is a likely disadvantage of introducing many microservices before operational maturity exists?

A. The system cannot have interfaces.

B. The system becomes unable to scale any component.

C. Distributed failure, deployment, testing, and observability complexity increase.

D. Business capabilities become impossible to identify.

Correct Answer: C. Distributed failure, deployment, testing, and observability complexity increase.

Question 7

A remote dependency is repeatedly failing. Which combination best limits cascading resource exhaustion?

A. Unlimited retries with no timeout

B. Circuit breaker, bounded timeout, and controlled retry with backoff

C. A larger class hierarchy

D. More synchronous calls to the same dependency

Correct Answer: B. Circuit breaker, bounded timeout, and controlled retry with backoff

Question 8

Which statement best describes a quality-attribute scenario?

A. A list of programming languages permitted by a team

B. A vague claim that the system should be good

C. A measurable statement connecting a stimulus, environment, response, and response goal

D. A diagram showing only database tables

Correct Answer: C. A measurable statement connecting a stimulus, environment, response, and response goal

Question 9

Why can strict layering create difficulties in some systems?

A. It prevents all testing.

B. It may create pass-through code, unnecessary coupling across layers, and performance overhead.

C. It eliminates the need for interfaces.

D. It always requires microservices.

Correct Answer: B. It may create pass-through code, unnecessary coupling across layers, and performance overhead.

Question 10

In the examination-platform case, why was reporting separated from critical answer recording?

A. Reporting had stronger consistency requirements than answer recording.

B. Reporting could tolerate temporary unavailability or lag, while accepted answers required integrity and durable recording.

C. Reporting could not use events.

D. Answer recording did not require a data owner.

Correct Answer: B. Reporting could tolerate temporary unavailability or lag, while accepted answers required integrity and durable recording.

Software Engineering
Chapter 4 of 15