Software Design and Scalable Web ArchitectureIntroduction and ContextWeb systems have evolved from relatively simple, centrally deployed applications into globally distributed platforms that must serve millions of users, integrate with external services, process asynchronous events, and remain available despite partial failures. Architecture is therefore not merely a matter of selecting a programming language or framework. It is the disciplined arrangement of software responsibilities, data, communication mechanisms, deployment units, and operational controls so that a system satisfies both functional and quality requirements. A scalable architecture must address several competing concerns. It should support changing business requirements without excessive modification, handle increasing workloads, isolate failures, preserve appropriate consistency, and remain understandable to the teams responsible for its operation. These goals often conflict. Strong consistency may increase latency; independent deployment may increase operational complexity; abstraction may improve flexibility but obscure performance costs. This chapter evaluates layered, modular, event-driven, serverless, microservice, and monolithic architectures through domain-driven design (DDD), SOLID principles, and common design patterns. It also examines scalability, resilience, messaging, consistency, and technical debt. The central argument is that architecture should be selected according to business boundaries, quality attributes, and organizational capability rather than technological fashion. Learning ObjectivesBy the end of this chapter, students should be able to: 1. Explain the purposes and trade-offs of major web architecture styles. 2. Apply domain-driven design to identify bounded contexts and service or module boundaries. 3. Use SOLID principles and design patterns to improve maintainability. 4. Distinguish vertical and horizontal scalability and select suitable scaling techniques. 5. Design for resilience using timeouts, retries, circuit breakers, bulkheads, and graceful degradation. 6. Compare synchronous communication, asynchronous messaging, and event-driven integration. 7. Analyse consistency, transactions, idempotency, and eventual consistency in distributed systems. 8. Evaluate monolithic, modular monolithic, microservice, serverless, and hybrid architectures. 9. Identify, measure, and manage technical debt. 10. Make architecture decisions using explicit trade-off analysis. 1. Architecture as a Set of DecisionsSoftware architecture comprises the significant decisions about a system’s structure, behaviour, deployment, and evolution. It includes components, interfaces, data ownership, communication protocols, runtime infrastructure, and constraints. Architecture is not identical to a diagram: a diagram describes structure, whereas architecture also includes rationale and quality attributes. Typical quality attributes include: - Performance: response time, throughput, and resource efficiency.
- Scalability: the ability to accommodate increased load by adding resources or improving capacity.
- Availability: the proportion of time a service is usable.
- Reliability: the probability that a system performs correctly over a specified period.
- Resilience: the ability to continue or recover operation after failures.
- Security: protection of confidentiality, integrity, availability, and accountability.
- Maintainability: the ease of correcting, modifying, and extending software.
- Deployability: the ability to release changes safely and frequently.
- Observability: the ability to infer internal state from logs, metrics, traces, and events.
Architecture decisions should be recorded with their context, alternatives, consequences, and assumptions. Architecture decision records are useful because they preserve reasoning that would otherwise disappear when personnel or requirements change. A useful decision sequence is: 1. Identify business capabilities and user journeys. 2. Define measurable quality attributes. 3. Determine workload characteristics and failure assumptions. 4. Establish ownership of data and business rules. 5. Compare architectural alternatives. 6. Build a small proof of concept for uncertain risks. 7. Record the decision and define indicators for revisiting it. 2. Layered and Modular Design2.1 Layered architectureLayered architecture separates responsibilities into levels. A common web arrangement contains: 1. Presentation layer: HTTP endpoints, controllers, views, and input validation. 2. Application layer: use-case orchestration, transaction boundaries, and authorization coordination. 3. Domain layer: business rules, entities, value objects, and domain services. 4. Infrastructure layer: databases, message brokers, file systems, external APIs, and framework integrations. The dependency rule normally directs dependencies toward more stable or central abstractions. For example, domain logic should not depend directly on a particular database driver. The application can depend on a repository interface while infrastructure supplies the implementation. This is associated with dependency inversion and is central to hexagonal or ports-and-adapters architecture. Layering improves comprehension, testing, and replacement of infrastructure. However, poorly implemented layering creates an “anemic” domain model in which business rules are scattered across controllers and database procedures. It may also produce excessive pass-through classes, duplicated data-transfer objects, and unnecessary performance overhead. 2.2 Modular architectureA module is a cohesive unit with a clear responsibility and controlled dependencies. Modularity is primarily about boundaries, not deployment. A modular monolith can contain multiple business modules in one deployable process. This frequently provides a useful intermediate state between a tightly coupled monolith and distributed microservices. Effective modules exhibit: - high internal cohesion;
- low coupling to other modules;
- explicit public interfaces;
- ownership of their business rules and data access;
- limited sharing of mutable state;
- independently testable behaviour.
A practical modular monolith may contain modules such as Catalog, Orders, Payments, and Delivery. Each module exposes application commands or queries rather than allowing arbitrary access to its tables. A later migration to services is easier when module boundaries already reflect business boundaries, although extracting a module still introduces network, deployment, and operational concerns. 3. Domain-Driven Design and Architectural BoundariesDomain-driven design focuses software design on the business domain and the language used by domain experts. It is especially valuable when business rules are complex and terminology has significant consequences. 3.1 Strategic designA domain is the overall business problem area. A subdomain is a meaningful part of that domain. Subdomains may be: - Core: the source of competitive differentiation.
- Supporting: important but not strategically unique.
- Generic: capabilities that can often be purchased or reused, such as basic identity or email delivery.
A bounded context is a boundary within which a domain model and its terms have a consistent meaning. For example, “customer” may mean a billing account in a Finance context and a delivery recipient in a Logistics context. Treating these as the same universal object often creates coupling and confusion. Context maps describe relationships between bounded contexts, such as supplier–consumer, conformist, anti-corruption layer, or published language. An anti-corruption layer translates an external model into the local model, preventing a legacy or third-party vocabulary from contaminating the core domain. 3.2 Tactical designImportant tactical concepts include: - Entity: an object defined by identity and continuity over time.
- Value object: an immutable object defined by its attributes, such as Money or Address.
- Aggregate: a consistency boundary containing related objects and one designated aggregate root.
- Repository: an abstraction for retrieving and persisting aggregates.
- Domain service: stateless domain behaviour that does not naturally belong to one entity.
- Domain event: a record that something meaningful has occurred in the domain.
- Application service: coordinates a use case but should not absorb core business rules.
Aggregates are particularly important for consistency. In a single transaction, invariants inside one aggregate can normally be enforced synchronously. Rules spanning several aggregates may require a process manager, saga, or eventual consistency. DDD does not prescribe microservices. A bounded context may be implemented as a module, a monolith component, or a separately deployed service. The key is semantic and ownership clarity. 4. SOLID Principles and Design PatternsSOLID principles are heuristics for object-oriented design and modularity. 4.1 Single Responsibility PrincipleA class or module should have one coherent reason to change. This does not mean that every class must contain one method. A payment module may contain several related operations while remaining responsible for payment behaviour. The principle is violated when one component mixes unrelated concerns such as pricing, email formatting, database migration, and HTTP rendering. 4.2 Open–Closed PrincipleSoftware entities should be open for extension but closed for unnecessary modification. Strategy and policy-based designs can support this principle. For example, shipping-cost calculation can depend on a ShippingPolicy interface with implementations for standard, express, and international delivery. 4.3 Liskov Substitution PrincipleA subtype should be usable wherever its abstraction is expected without breaking correctness. Violations occur when an implementation rejects valid inputs promised by the interface or changes important postconditions. 4.4 Interface Segregation PrincipleClients should not depend on methods they do not use. Small, role-specific interfaces reduce coupling and make testing easier. A reporting client should not be forced to depend on administrative mutation operations. 4.5 Dependency Inversion PrincipleHigh-level policy should not depend directly on low-level mechanisms. Both should depend on abstractions. Dependency injection is a common implementation technique, but dependency inversion is a design relationship, not merely a framework feature. Useful patterns include: - Adapter: translates one interface or model into another.
- Facade: presents a simpler interface to a complex subsystem.
- Strategy: encapsulates interchangeable algorithms or policies.
- Factory: centralizes controlled object creation.
- Repository: abstracts aggregate persistence.
- Unit of Work: coordinates changes within a transaction.
- Outbox: stores an event in the same local transaction as a business update, then publishes it asynchronously.
- Circuit breaker: prevents repeated calls to a failing dependency.
- Saga: coordinates a distributed business process through local transactions and compensating actions.
Patterns are not universally beneficial. A pattern introduces concepts and maintenance cost; it should solve an observed design problem rather than decorate a design with fashionable terminology. 5. Comparing Major Architecture Styles5.1 Monolithic architectureA monolith is deployed as one primary unit. It may be poorly structured or highly modular; “monolith” describes deployment more than code quality. Advantages include simple local calls, straightforward transactions, low operational overhead, and easy development for small teams. Disadvantages include broad deployment scope, potential coupling, and the possibility that a defect or resource problem affects the entire application. Scaling may also be inefficient when only one feature requires additional capacity. A well-designed modular monolith is often appropriate when the domain is still uncertain, the team is small, or transaction coordination is important. 5.2 MicroservicesMicroservices are independently deployable services organized around business capabilities, each owning a bounded context and usually its data. They enable selective scaling, team autonomy, and independent release. They also introduce network latency, distributed tracing, service discovery, versioning, partial failure, data duplication, operational cost, and difficult cross-service transactions. A service should not be created merely because a database table or technical layer exists. Strong candidates have a stable business boundary, clear ownership, an independently meaningful deployment need, and a team capable of operating them. 5.3 Event-driven architectureIn event-driven systems, components communicate through events representing facts, such as OrderPlaced or PaymentAuthorized. Producers do not necessarily know every consumer. This supports loose coupling, asynchronous processing, and multiple reactions to one business event. Events must have defined schemas, ownership, versioning rules, retention policies, and privacy controls. Eventual consistency is common, so user interfaces should communicate processing states rather than pretending that all projections update immediately. Event notification, event-carried state transfer, and event sourcing are distinct. Event sourcing stores domain events as the primary record of state; it is not required for ordinary event-driven integration. 5.4 Serverless architectureServerless platforms abstract much infrastructure management and commonly charge according to invocation, execution, or provisioned capacity. Functions can scale rapidly and are useful for event handlers, scheduled jobs, APIs, and irregular workloads. Constraints include startup latency, execution limits, platform-specific interfaces, difficult local debugging, distributed observability, concurrency surprises, and dependence on managed services. Serverless does not mean there are no servers; it means the provider manages most server provisioning and operations. 5.5 Hybrid architectureMost large systems are hybrid. A modular core may expose synchronous APIs, publish events, invoke serverless processors, and use separately deployed services for high-volume or independently governed capabilities. Hybrid designs require explicit boundaries and consistent operational standards; otherwise they become accidental complexity. 6. Scalability and Capacity ReasoningVertical scaling increases the capacity of one resource, such as adding memory or CPU. It is simple but has physical and economic limits. Horizontal scaling adds instances and normally requires stateless application processes, shared or partitioned storage, load balancing, and coordination of sessions and caches. A basic capacity estimate is: \[ \text{Throughput} = \frac{\text{completed requests}}{\text{time interval}} \] Throughput is commonly measured in requests per second. This definition describes observed work and does not by itself guarantee acceptable latency. For a stable system, Little’s Law provides a useful relationship: \[ L = \lambda W \] where L is the average number of items in the system, λ is the average arrival rate, and W is the average time an item spends in the system. The assumptions include a stable system over the measurement interval and compatible averages. For example, if a service receives 200 requests per second and the average response time is 0.25 seconds, the average number of in-process requests is 50. This is a capacity-planning relationship, not a performance guarantee. Scalability techniques include: - stateless web servers behind a load balancer;
- caching with explicit invalidation or acceptable staleness;
- database indexing and query optimization;
- read replicas for read-heavy workloads;
- partitioning or sharding when a single data store becomes a bottleneck;
- asynchronous queues for work that need not complete during the request;
- backpressure to prevent producers from overwhelming consumers;
- content delivery networks for geographically distributed static content.
Caching requires careful analysis of freshness, invalidation, privacy, and failure behaviour. A cache can reduce database load but can also return stale or unauthorized data if keys and access controls are poorly designed. 7. Resilience and Failure DesignDistributed systems fail partially. A dependency may be slow rather than unavailable; a network may lose a response after the remote operation has completed; or a queue consumer may process a message twice. Essential resilience mechanisms include: - Timeouts: bound waiting time and prevent resource exhaustion.
- Retries: repeat transient failures, preferably with exponential backoff and jitter. Retries must be limited and used only when the operation is safe or idempotent.
- Circuit breakers: temporarily stop calls to a failing dependency, allowing recovery and protecting callers.
- Bulkheads: isolate resource pools so that one workload cannot consume all threads, connections, or memory.
- Rate limiting: restrict request volume to protect the system and enforce fairness.
- Health checks: distinguish process liveness from readiness to serve traffic.
- Graceful degradation: provide reduced functionality when optional components fail.
- Dead-letter queues: isolate messages that cannot be processed successfully.
Reliability engineering must consider correlated failures. Multiple replicas in one failure domain do not provide the same protection as replicas across independent zones. Recovery objectives should be explicit: recovery time objective concerns how quickly service must be restored, while recovery point objective concerns the acceptable amount of data loss measured in time. Observability combines logs, metrics, traces, and domain events. Correlation identifiers should follow a request across services. Metrics should include both technical indicators, such as latency and error rate, and business indicators, such as completed orders or failed payments. 8. Messaging, Transactions, and ConsistencySynchronous HTTP or RPC is appropriate when a caller requires an immediate response and the dependency is part of the current user experience. Asynchronous messaging is appropriate for long-running, bursty, retryable, or independently processed work. Message delivery semantics are often described as: - At-most-once: a message may be lost but is not intentionally redelivered.
- At-least-once: messages are retried, so duplicates are possible.
- Exactly-once effect: the business outcome occurs once, usually through idempotency and transactional design rather than a magical transport guarantee.
An idempotent operation can be repeated with the same input without changing the intended result after the first successful application. Payment commands commonly use an idempotency key stored with the result. Consumers should also record processed message identifiers where appropriate. The outbox pattern addresses a dual-write problem. If a service updates an order database and separately publishes an event, a failure between those actions can create inconsistency. The service instead writes the order change and an outbox record in one local transaction. A publisher later reads the outbox and sends the event, marking it as published. Duplicate publication remains possible, so consumers must be idempotent. Strong consistency means readers observe updates according to a strict coordination model. Eventual consistency means that, if updates stop, replicas or projections eventually converge. Eventual consistency can be acceptable for search indexes, recommendations, and reporting, but it may be unsuitable for enforcing a financial invariant without additional safeguards. A saga coordinates a business process across local transactions. In a choreography-based saga, services react to events. In an orchestration-based saga, a coordinator directs steps. Compensation is a new business action that semantically reverses or offsets a previous action; it is not necessarily a database rollback. For example, cancelling a shipment is not identical to undoing the fact that a courier was already dispatched. 9. Technical Debt and EvolutionTechnical debt is the future cost created by expedient decisions, obsolete dependencies, insufficient tests, architectural shortcuts, or deferred maintenance. Not all debt is irresponsible: a deliberate prototype may be rational if its expiration and replacement conditions are explicit. Unmanaged debt becomes dangerous when it slows delivery, increases defects, or prevents architectural change. Indicators include increasing change lead time, frequent regression, rising incident volume, duplicated logic, dependency vulnerabilities, declining test reliability, and high coupling between modules. Debt should be documented with its cause, impact, risk, and repayment strategy. Useful repayment practices include: - modular refactoring during feature work;
- automated characterization tests before changing legacy code;
- strangler migration, in which new functionality gradually replaces old functionality;
- anti-corruption layers around legacy systems;
- dependency upgrades and removal of unused components;
- architecture fitness functions that continuously check boundaries;
- explicit capacity allocation for reliability and maintenance.
Architecture governance should avoid central approval of every class design. A better approach combines principles, lightweight review, automated checks, security controls, and team ownership. 10. Illustrative Case: A Growing Online MarketplaceBackgroundThis illustrative case concerns “MarketHub,” an online marketplace that began as a single application. It supports product browsing, shopping carts, orders, payments, seller fulfilment, notifications, and reporting. ProblemThe application initially used shared tables and synchronous calls. As traffic grew, checkout became slow during promotional campaigns. A reporting query consumed database resources, delaying customer requests. Releases were risky because a change to seller fulfilment required redeploying the entire application. The team proposed immediately dividing the system into twelve microservices. AnalysisThe architects first mapped the domain. Catalog, Ordering, Payments, Fulfilment, and Reporting were distinct capabilities. They found that Catalog and Reporting had different scaling characteristics, while Ordering and Payments contained important transactional and compliance rules. They also discovered that the organization had one operations team and limited experience with distributed tracing. The quality priorities were checkout correctness, predictable latency, independent scaling of read-heavy workloads, and safer deployment. Maximum service count was not a stated business requirement. Approach and solutionThe team selected a modular monolith as the first architectural step. Each domain module received an explicit API and controlled data access. The Reporting module was separated into a read model populated by order events. An outbox ensured reliable publication of OrderPlaced events. Catalog search was moved to a separately scaled search index, while payment integration remained behind an adapter and idempotent application service. Checkout retained a local transaction for the order aggregate. Fulfilment was handled asynchronously after the order was accepted. The user interface displayed “Order accepted; fulfilment processing” rather than implying that every downstream action had completed. Timeouts, bounded retries, correlation identifiers, dashboards, and dead-letter handling were introduced. Later, when fulfilment required independent release cycles and its traffic profile diverged significantly, it was extracted as a service. The extraction reused the existing module boundary and event contract. OutcomeReporting no longer competed directly with transactional queries. Checkout latency became more predictable, and deployment risk decreased because module ownership and tests were clearer. The system still retained a monolithic core, but it had a deliberate path for selective extraction. Operational complexity increased only where the business case justified it. Learning points1. A modular monolith can be an advanced and scalable design, not merely a temporary failure state. 2. Event-driven read models can isolate workloads without making every capability a service. 3. Extraction should follow stable business and operational boundaries. 4. Idempotency and observability are essential when asynchronous processing is introduced. 5. Architecture decisions should reflect team capability as well as theoretical scalability. 11. Governance, Security, and Ethical ConsiderationsArchitecture affects legal and ethical responsibilities. Data ownership boundaries should reflect privacy obligations and data minimization. Personally identifiable information should not be copied into events or logs without a justified purpose. Retention, deletion, access control, encryption, and auditability must be designed rather than added after deployment. Distributed systems complicate authorization because identity and permissions cross service boundaries. Services should validate authorization for their own resources rather than trusting a user interface or an upstream service blindly. Secrets require managed storage and rotation. Reliability also has ethical implications. Failure of a healthcare, financial, or public-service system can harm users. High-risk systems require stronger validation, incident response, audit trails, accessibility, and human escalation. Automated decision-making should be explainable to the extent required by the domain and applicable regulation. AI-enabled services introduce additional concerns: model latency and cost, nondeterministic outputs, prompt or data leakage, biased decisions, and changing model behaviour. AI components should be isolated behind explicit interfaces, monitored for quality and safety, and prevented from making irreversible decisions without appropriate controls. 12. Contemporary Directions and Best PracticesCurrent architecture practice increasingly emphasizes platform engineering, internal developer platforms, managed data services, container orchestration, zero-trust security, and software supply-chain security. These technologies can reduce repetitive operational work, but they do not remove the need for domain modelling or sound boundaries. Recommended practices include: - begin with business capabilities and quality attributes;
- prefer modularity before distribution;
- keep ownership of data and business rules explicit;
- use synchronous calls only where immediate coordination is required;
- use asynchronous messaging for durable, independent work;
- make consumers idempotent and messages versioned;
- establish timeouts, bounded retries, and bulkheads by default;
- measure latency, throughput, saturation, errors, and business outcomes;
- test failure modes, not only successful paths;
- automate security, dependency, and architecture checks;
- document decisions and revisit assumptions as the system evolves.
The most scalable architecture is not necessarily the one with the most services. It is the one whose boundaries, data flows, operational practices, and organizational capabilities remain sustainable as demand and complexity grow. Chapter SummaryScalable web architecture is a balance of structure, behaviour, operations, and business purpose. Layered and modular designs improve separation of concerns, while domain-driven design provides a method for discovering meaningful business boundaries. SOLID principles and design patterns support change, but they must be applied selectively. Monoliths provide simplicity and local transactions; modular monoliths preserve these benefits while improving boundaries. Microservices support independent deployment and scaling but introduce distributed-systems complexity. Event-driven and serverless architectures can improve decoupling and elasticity, yet require disciplined messaging, observability, security, and cost management. Scalability involves both capacity and latency. Resilience requires designing for partial failure through timeouts, retries, circuit breakers, bulkheads, graceful degradation, and recovery planning. Messaging commonly provides at-least-once delivery, making idempotency essential. The outbox pattern helps coordinate database changes and event publication, while sagas manage long-running distributed processes through local transactions and compensation. Technical debt is an architectural liability when shortcuts are unmanaged. Incremental modularization, automated tests, architecture fitness functions, and evidence-based extraction provide safer evolution. Effective architecture is therefore less about selecting a fashionable style and more about making explicit, measurable, and revisable decisions. Key Terms- Aggregate: A consistency boundary containing related domain objects and one aggregate root.
- Architecture decision record: A concise record of an architectural decision, context, alternatives, and consequences.
- Bounded context: A boundary within which a domain model and terminology have consistent meaning.
- Circuit breaker: A mechanism that temporarily stops calls to a failing dependency.
- Domain event: A representation of a meaningful occurrence in a business domain.
- Domain-driven design: An approach that centres software design on domain concepts and business language.
- Eventual consistency: A model in which distributed representations converge after updates stop.
- Idempotency: The property that repeating an operation does not produce additional unintended effects.
- Layered architecture: An arrangement of responsibilities into levels with controlled dependencies.
- Microservice: An independently deployable component organized around a business capability or bounded context.
- Modular monolith: A single deployment containing strongly separated business modules.
- Outbox pattern: A technique that records a business change and its outgoing event in one local transaction.
- Resilience: The ability to continue or recover operation after failures.
- Saga: A distributed business process composed of local transactions and compensating actions.
- Scalability: The ability to accommodate increased workload through additional or improved capacity.
- SOLID: Five principles supporting maintainable object-oriented and modular design.
- Technical debt: Future cost caused by expedient, deficient, or outdated technical decisions.
- Value object: An immutable domain object defined by its attributes rather than identity.
Review QuestionsShort Answer Questions1. What is the difference between a monolithic deployment and a modular monolith? 2. Define a bounded context and explain why terminology may differ between contexts. 3. Why are timeouts important in distributed web systems? 4. What problem does the outbox pattern address? 5. Distinguish vertical scaling from horizontal scaling. Long Answer Questions1. Compare monolithic, modular monolithic, and microservice architectures in terms of deployment, transactions, scalability, and operational complexity. 2. Explain how domain-driven design can guide service or module boundaries. 3. Discuss the SOLID principles and show how at least three can improve web application maintainability. 4. Explain event-driven architecture, including event schemas, delivery semantics, idempotency, and eventual consistency. 5. Analyse the role of resilience patterns in a system that depends on several external services. Analytical / Application Questions1. A university registration platform has a small development team, complex enrolment rules, and moderate traffic. Recommend an initial architecture and justify your decision using domain and operational factors. 2. An online retailer receives 150 requests per second and has an average response time of 0.4 seconds. Using Little’s Law, estimate the average number of requests in the system and state the assumptions behind the calculation. 3. Design an order-processing flow using an outbox and saga approach. Identify the local transactions, events, possible failures, compensating actions, and user-visible consistency expectations. Multiple Choice Questions with AnswersQuestion 1Which statement best describes a bounded context? A. A database table shared by every service B. A boundary within which a domain model and terminology have consistent meaning C. A network zone containing only authenticated users D. A deployment pipeline for one application Correct Answer: B. A boundary within which a domain model and terminology have consistent meaning Question 2What is the principal purpose of the dependency inversion principle? A. To make all classes inherit from one base class B. To eliminate the need for interfaces C. To make high-level policy independent of low-level implementation details D. To ensure every service uses a separate database Correct Answer: C. To make high-level policy independent of low-level implementation details Question 3A service receives 200 requests per second and has an average response time of 0.25 seconds. Under Little’s Law, what is the average number of requests in the system? A. 50 B. 80 C. 200 D. 800 Correct Answer: A. 50 Question 4Which pattern records a business update and its outgoing event in the same local transaction? A. Adapter B. Outbox C. Facade D. Circuit breaker Correct Answer: B. Outbox Question 5Why must consumers commonly be idempotent in an at-least-once messaging system? A. Messages are guaranteed to arrive in order B. Duplicate delivery can occur C. It prevents all network latency D. It makes transactions globally serializable Correct Answer: B. Duplicate delivery can occur Question 6Which architecture characteristic is most strongly associated with a modular monolith? A. Every module must run in a separate cloud account B. The application has no domain boundaries C. Modules are strongly separated while sharing one primary deployment D. All communication must use a message broker Correct Answer: C. Modules are strongly separated while sharing one primary deployment Question 7What is the main purpose of a circuit breaker? A. To encrypt service-to-service traffic B. To stop repeated calls to a failing dependency temporarily C. To guarantee exactly-once message delivery D. To replace database indexes Correct Answer: B. To stop repeated calls to a failing dependency temporarily Question 8Which statement about a saga is correct? A. It always performs one distributed ACID transaction B. It coordinates local transactions and may use compensating actions C. It is only applicable to serverless functions D. It eliminates the need for observability Correct Answer: B. It coordinates local transactions and may use compensating actions Question 9Which is a major trade-off introduced by microservices? A. They remove the need for deployment automation B. They eliminate network failures C. They enable independent deployment but increase distributed-systems complexity D. They require all business rules to be placed in the database Correct Answer: C. They enable independent deployment but increase distributed-systems complexity Question 10Which practice best protects a domain model from an external legacy model? A. Allowing direct access to the legacy database from every module B. Using an anti-corruption layer C. Duplicating all legacy classes unchanged D. Removing domain terminology from the application Correct Answer: B. Using an anti-corruption layer
|