6. Application Architecture and ModernizationIntroduction and ContextKubernetes can schedule containers, restart failed workloads, expose services, and coordinate distributed deployments. It cannot, by itself, determine whether an application has been decomposed wisely, whether its data boundaries are coherent, or whether a legacy system should be replaced, refactored, or retained. Those decisions belong to application architecture. Application architecture describes the significant structures, responsibilities, interactions, and constraints of a software system. In cloud-native environments, architecture is closely related to deployment architecture, but the two are not identical. A set of containers is not automatically a set of microservices, and moving an existing application to Kubernetes does not necessarily modernize it. Modernization requires deliberate changes to software structure, delivery practices, operational behavior, and sometimes organizational ownership. This chapter examines the principal architectural approaches used in cloud-native development: microservices, modular monoliths, event-driven systems, APIs, messaging, sidecars, twelve-factor principles, and domain-driven design. It also considers how organizations evaluate decomposition, migrate legacy systems, and apply the strangler pattern. The central concern is not whether one architecture is universally superior. Rather, it is how to select an appropriate architecture for a particular domain, team structure, risk profile, and modernization objective. Learning ObjectivesAfter studying this chapter, the learner should be able to: 1. Explain the relationships among application architecture, deployment architecture, and cloud-native design. 2. Distinguish a modular monolith from a microservices architecture and evaluate when each is appropriate. 3. Apply domain-driven design concepts to service and module boundaries. 4. Analyze synchronous APIs, asynchronous messaging, and event-driven interactions. 5. Explain the role and limitations of sidecars in Kubernetes-based systems. 6. Use twelve-factor principles to assess application readiness for cloud-native operation. 7. Compare modernization strategies, including rehosting, refactoring, rearchitecting, and replacement. 8. Design a reasoned strangler-pattern migration for a legacy application. 9. Identify technical, organizational, security, governance, and operational risks in architectural change. Architecture as a Set of Boundaries and DecisionsAn architecture is more than a diagram. It is a set of decisions about responsibilities, dependencies, data ownership, communication, deployment, quality attributes, and change. A useful architecture makes important decisions visible and constrains future change in beneficial ways. Cloud-native architecture typically seeks elasticity, failure isolation, independent delivery, automation, observability, and portability of operational concerns. These goals create benefits but also introduce distributed-systems problems. Network calls can fail, messages can be duplicated, clocks can differ, partial deployment can occur, and data consistency may become eventual rather than immediate. Consequently, decomposing an application is not simply a matter of dividing source code into smaller repositories. Three boundaries are especially important. A functional boundary separates business responsibilities. A data boundary defines which component owns and changes particular data. A operational boundary determines what can be deployed, scaled, secured, and monitored independently. A design becomes fragile when these boundaries conflict. For example, two proposed services may have separate code repositories but depend on the same database tables and must always be released together. Their deployment boundary is therefore largely artificial. Architecture also reflects organizational structure. Teams that own a service should possess sufficient knowledge and authority to develop, deploy, operate, and improve it. This relationship is often expressed through the idea that communication structures influence software structures. It does not mean that an organization should reorganize merely to create microservices; it means that service boundaries and team responsibilities should be considered together. Choosing Between a Modular Monolith and MicroservicesA monolith is an application deployed as one unit. The term does not necessarily imply poor design. A modular monolith is a single deployable application whose internal modules have explicit interfaces, controlled dependencies, separate domain responsibilities, and, ideally, clear ownership of data. It may provide strong transactional consistency and straightforward local calls while preserving architectural boundaries. Microservices are independently deployable services organized around business capabilities. Each service generally owns a bounded context, controls its data, and communicates through explicit APIs or messages. Independent deployment and scaling are important characteristics, but the word “micro” refers more to scope and responsibility than to a prescribed code size. A modular monolith is often preferable when the domain is poorly understood, the team is small, transactional coupling is high, or independent scaling is not required. It reduces network failure modes, simplifies debugging, and allows architectural learning before operational complexity is introduced. A well-designed modular monolith can later provide extraction seams if a particular module becomes a strong candidate for independent deployment. Microservices become more compelling when parts of a system have significantly different scaling profiles, release cadences, security requirements, technology constraints, or ownership structures. They are also useful when failure isolation and independent evolution are important. However, microservices impose costs: distributed tracing, contract management, network latency, operational tooling, version compatibility, data synchronization, and more complex testing. The decision should therefore be based on evidence rather than fashion. Useful evaluation questions include: - Does the proposed boundary correspond to a meaningful business capability?
- Can the component own its data and rules without frequent database-level coordination?
- Can a team deploy it without coordinating every release with other teams?
- Is independent scaling or failure isolation valuable?
- Are the team’s operational skills and platform capabilities sufficient?
- What consistency and latency requirements must be preserved?
A common mistake is to begin with technical layers such as “user interface service,” “database service,” and “business logic service.” Such decomposition usually reproduces a distributed three-tier monolith. A more durable approach begins with business capabilities and the decisions that change together. Domain-Driven Design and the Discovery of BoundariesDomain-driven design (DDD) provides a vocabulary and method for connecting software structure to business structure. It is particularly useful when a domain contains complex rules, multiple interpretations, and competing stakeholder concerns. The domain is the area of business knowledge addressed by the system. A subdomain is a distinguishable part of that domain. Subdomains may be core, supporting, or generic. The core subdomain is strategically important and often deserves specialized design effort. A generic subdomain, such as basic authentication, may be implemented using an existing product rather than developed internally. A bounded context is a boundary within which a domain model and its terminology have consistent meaning. The term “account,” for example, may refer to a customer account in one context and a ledger account in another. Treating both as one universal object can create ambiguity and excessive coupling. Separate bounded contexts may communicate through explicit contracts and translation mechanisms. DDD also emphasizes a ubiquitous language shared by domain experts and developers. This language should appear in requirements, code, tests, APIs, and operational documentation. If stakeholders use different meanings for the same term, the disagreement is an architectural signal rather than merely a vocabulary problem. Strategic DDD helps identify contexts and relationships among them. A context map may describe relationships such as customer-supplier, conformist, partnership, or anti-corruption layer. An anti-corruption layer protects one model from the assumptions and data representations of another. During modernization, it is particularly valuable when a new service must interact with a legacy system without adopting the legacy system’s internal abstractions. Tactical DDD concerns implementation patterns such as entities, value objects, aggregates, domain services, repositories, and domain events. An aggregate is a consistency boundary with one aggregate root through which external changes are controlled. Overly large aggregates create contention and reduce scalability; overly small aggregates may make business invariants difficult to enforce. The appropriate boundary depends on the invariant that must be protected, not on the number of classes. DDD does not mechanically produce microservices. A bounded context may be implemented as a module in a monolith, a service, or part of a larger platform. DDD is a way of understanding and modeling the domain; microservices are one possible deployment and organizational choice. APIs, Messaging, and Event-Driven InteractionDistributed applications interact through contracts. An API is a defined interface through which one component requests capabilities or exchanges information with another. APIs may be synchronous, asynchronous, internal, external, command-oriented, or query-oriented. HTTP and REST-style APIs are common for request-response interactions. They work well when a caller needs an immediate result, such as retrieving a product catalogue or submitting a validated command. Good API design requires stable resource or capability semantics, explicit error behavior, authentication and authorization, versioning discipline, idempotency where appropriate, and observability. A technically valid API can still be poor if it exposes internal database tables, forces chatty call sequences, or makes consumers depend on implementation details. Idempotency means that repeating an operation has the same intended effect as performing it once. It is essential when clients retry after timeouts. An idempotency key, stored operation record, or naturally idempotent update can prevent duplicate charges, orders, or provisioning actions. Timeouts must not be interpreted as proof that an operation failed; the operation may have completed while the response was lost. Messaging decouples a sender from a receiver in time, location, or processing speed. A queue generally distributes work to one consumer or consumer group, whereas a topic or event stream allows multiple interested consumers to receive a record. Messaging improves resilience and enables asynchronous workflows, but it introduces concerns about ordering, duplication, retention, replay, dead-letter handling, schema evolution, and monitoring. An event records something that has happened, such as `OrderPlaced`. A command asks that something happen, such as `CreateShipment`. Confusing the two can produce unclear contracts. Events should normally be expressed as facts and should not require consumers to understand the producer’s internal object model. Event-driven architecture uses events to coordinate components. It may be used for integration, data propagation, workflow coordination, or analytics. It does not eliminate coupling; it changes the form of coupling. Producers and consumers remain coupled through event meaning, schema, timing assumptions, and operational expectations. Eventual consistency must be communicated to users and reflected in business processes. Reliable publication of an event alongside a database transaction is a recurring challenge. A common solution is the transactional outbox pattern. The service writes its business change and an outbox record in one local transaction. A separate publisher reads the outbox and sends the event to the broker. Consumers process events idempotently, because publication or delivery may be repeated. This pattern improves reliability but requires outbox cleanup, monitoring, retry policies, and reconciliation. Distributed transactions should not be introduced casually. A saga coordinates a long-running business transaction through a sequence of local transactions. If a later step fails, compensating actions attempt to restore an acceptable business state. A saga may be choreography-based, where participants react to events, or orchestration-based, where a coordinator directs steps. Compensation is not always a technical rollback: cancelling a shipment, issuing a refund, or contacting a customer may be a new business action with its own consequences. Sidecars and the Separation of Application and Platform ConcernsA sidecar is a supporting process deployed alongside an application component, often in the same Kubernetes Pod. It shares certain lifecycle and networking characteristics with the main container and can provide capabilities such as proxying, telemetry collection, certificate handling, configuration assistance, or protocol translation. Sidecars are associated with service-mesh architectures, in which proxies may provide mutual TLS, traffic policy, retries, circuit breaking, and telemetry without requiring every application team to implement those features independently. This can standardize platform behavior and accelerate adoption of cross-cutting capabilities. However, sidecars are not free. They consume CPU and memory, add network hops, complicate troubleshooting, and can obscure the actual behavior of an application. Automatic retries may amplify load; timeouts configured at multiple layers may conflict; and a proxy cannot correct an application-level misunderstanding of business semantics. Sidecars should therefore be introduced for a clear operational purpose, with resource accounting and failure analysis. The sidecar pattern is one form of the broader principle of separating business logic from platform capabilities. In some cases, a node-level agent, gateway, library, or managed platform service is more suitable. The correct choice depends on scope, lifecycle, performance, and ownership. Twelve-Factor Principles in Kubernetes ApplicationsThe twelve-factor approach offers a practical set of principles for building services that can be deployed across environments. Its principles remain useful, although modern platforms sometimes extend or reinterpret them. 1. One codebase: A service should have a controlled codebase with distinct deployments derived from it. 2. Explicit dependencies: Dependencies should be declared rather than assumed to exist on a server image. 3. Config in the environment: Environment-specific values such as credentials, endpoints, and feature settings should not be hard-coded. Kubernetes ConfigMaps and Secrets can support this principle, subject to secure handling. 4. Backing services as attached resources: Databases, brokers, and storage services should be replaceable through configuration and contracts. 5. Build, release, run separation: Building an artifact, combining it with configuration, and running it should be distinct stages. 6. Stateless processes: Durable state should reside in appropriate backing services rather than in the local container filesystem. 7. Port binding: Services should expose themselves through explicit ports rather than relying on a preconfigured application server. 8. Concurrency through processes: Scaling should use independent processes or replicas where appropriate. 9. Disposability: Processes should start quickly and shut down gracefully, supporting replacement and autoscaling. 10. Development and production parity: Differences among environments should be minimized. 11. Logs as event streams: Applications should emit structured logs and allow the platform to collect and route them. 12. Administrative tasks: Migration, reconciliation, and maintenance tasks should be executable as controlled processes rather than ad hoc changes on servers. These principles do not mean that every application must be stateless or that every database must be externally managed. They provide questions for architectural assessment. A stateful workload may be appropriate, but its storage, backup, failover, and recovery behavior must be explicit. Modernization: From Legacy Constraints to Incremental ChangeModernization begins with a clear objective. An organization may seek faster delivery, reduced infrastructure cost, improved resilience, regulatory compliance, better customer experience, or access to analytical capabilities. “Move to Kubernetes” is an implementation decision, not a sufficient business objective. Several strategies form a spectrum: - Retain: Keep the existing system when its capabilities remain adequate and change risk is high.
- Rehost: Move the system with minimal code change, often to virtual machines or containers. This may improve infrastructure consistency but does not remove architectural limitations.
- Replatform: Make limited changes, such as adopting a managed database or externalizing configuration.
- Refactor: Improve internal structure without changing the overall externally visible behavior.
- Rearchitect: Change major components, data flows, or deployment boundaries to achieve qualities that the current architecture cannot provide.
- Rebuild or replace: Develop a new solution when the existing system is uneconomical or incapable of meeting essential requirements.
These options should be evaluated using business value, technical feasibility, migration risk, time, skills, and operational cost. A technically elegant replacement may be strategically inferior if it delays essential capabilities for several years. A useful modernization assessment inventories business capabilities, dependencies, data stores, interfaces, batch jobs, operational procedures, compliance obligations, and undocumented assumptions. Runtime observation is often as important as source-code inspection. Logs, traces, database access patterns, deployment history, and incident records can reveal actual coupling. The Strangler Pattern as a Migration StrategyThe strangler pattern replaces a legacy system incrementally. A new capability is built around or beside the old system, traffic is routed selectively, and the legacy path is reduced until it can be retired. The approach is named after a plant that grows around and eventually encloses its host, but in software the process must be governed carefully; otherwise both systems may persist indefinitely. A strangler migration normally includes the following activities: 1. Define a target capability and measurable outcome. 2. Establish an anti-corruption layer or façade around legacy interfaces. 3. Capture baseline behavior, performance, and error rates. 4. Implement the new path with explicit contracts and observability. 5. Route a controlled segment of traffic using gateway rules, feature flags, or routing policies. 6. Compare outcomes and retain a rapid rollback mechanism. 7. Migrate data deliberately, using synchronization, dual reading, controlled dual writing, or a planned cutover. 8. Remove obsolete routes, code, data paths, and operational procedures. The first slice should not necessarily be the easiest function. It should be valuable enough to justify learning and sufficiently bounded to control risk. A capability with clear ownership and limited cross-domain transactions is often a better candidate than a central function whose behavior is entangled with every legacy module. Traffic migration is only one part of strangulation. Data migration is usually harder. If the old and new systems both write the same business data, conflicts and ordering problems can arise. Dual writes without reconciliation are particularly risky. Migration designs should define the authoritative source, consistency expectations, reconciliation procedures, failure handling, and retirement criteria. Illustrative Case: Modernizing a Retail Order PlatformBackgroundThe following is an illustrative case. Meridian Retail operates an online and physical-store business using a twelve-year-old order-management application. The application contains order capture, payment coordination, inventory reservation, shipment requests, customer notifications, and reporting in one deployable unit. It uses a shared relational database with numerous tables accessed by multiple modules. Situation and ProblemRelease coordination requires several teams to deploy together. A small change to delivery notifications can require regression testing of payment and inventory functions. During seasonal demand, the entire application is scaled even though only order capture experiences a major increase. The business wants faster releases and better resilience, but it cannot accept a high-risk replacement project. AnalysisArchitecture workshops identify four bounded contexts: ordering, inventory, fulfilment, and customer communication. Payment remains integrated initially because regulatory controls and transaction semantics are tightly coupled to the existing payment module. The workshops also reveal that “available inventory” has different meanings for online ordering and store replenishment. Treating it as one universal object had produced several defects. Runtime traces show that notification processing is asynchronous in business terms but is currently executed synchronously within the order request. This creates unnecessary latency. Inventory reservation, by contrast, must provide a clear response before an order is confirmed. The proposed design therefore distinguishes synchronous commands from asynchronous events. ApproachMeridian first places an API façade in front of the legacy application. The façade provides stable external contracts and records correlation identifiers. A new notification service subscribes to an `OrderConfirmed` event. Initially, the legacy application continues to send notifications, but a feature flag permits controlled traffic to the new service for selected regions. The transactional outbox pattern is added to the order module so that order confirmation and event publication are recorded reliably. The notification service owns message templates and delivery preferences. It does not access legacy notification tables directly. An anti-corruption layer translates legacy customer and order representations into the new service’s model. Duplicate events are expected and handled through an idempotency record. After several release cycles, the legacy notification path is disabled for the migrated regions. The obsolete tables and code are removed only after reconciliation reports show that all required messages have been accounted for. The next slice is inventory availability, but the team first models reservation rules and defines which system is authoritative for each inventory category. Kubernetes provides independent deployment, autoscaling for notification workers, health checks, secret integration, and standardized telemetry; it does not replace the need for domain decisions. OutcomeThe organization obtains an independently deployable notification capability and reduces the latency of order confirmation. More importantly, it develops a repeatable migration method: establish a boundary, create a contract, observe behavior, route gradually, reconcile data, and retire obsolete paths. The case does not claim that all components should become services. Payment and order confirmation remain more tightly coordinated because the business invariants justify that coupling. Learning PointsThe case demonstrates that modernization is a sequence of controlled architectural changes rather than a single platform migration. Events are useful where work is naturally asynchronous, while synchronous interaction remains appropriate where an immediate business decision is required. Independent deployment is valuable only when ownership, data boundaries, and operational readiness support it. Risks, Governance, and Professional ResponsibilitiesDistributed architecture increases the number of failure modes. A service may be healthy while a dependency is unavailable; a message may be delayed; a consumer may process an event twice; and a deployment may create incompatible contracts. Reliability must therefore be designed through timeouts, bounded retries, circuit breaking where appropriate, dead-letter handling, idempotency, backpressure, graceful degradation, and reconciliation. Security boundaries must be explicit. Service identity, least-privilege authorization, encryption in transit, secret rotation, audit trails, and network policies are architectural concerns. A service mesh can support mutual TLS, but encryption does not establish business authorization. An authenticated service may still be forbidden to perform a particular operation. Data governance becomes more difficult when data is replicated across services and event streams. Teams should classify sensitive data, limit unnecessary propagation, define retention periods, protect personally identifiable information, and support deletion or correction obligations. Event immutability can conflict with privacy requirements; designs may require tokenization, encryption, redaction, or controlled deletion strategies. APIs and event schemas are organizational contracts. Compatibility rules, ownership, deprecation periods, documentation, consumer testing, and change approval should be proportionate to risk. Contract testing can detect whether a provider change breaks known consumer expectations, but it cannot replace domain-level validation. Common mistakes include creating services around technical layers, sharing databases while claiming independent ownership, using events for every interaction, adding retries without idempotency, migrating code without migrating operational practices, and adopting a service mesh before the organization can manage its complexity. Another mistake is measuring modernization by the number of containers or services. Better measures include lead time, change failure rate, recovery time, business capability delivery, incident frequency, cost per transaction, and successful retirement of legacy components. Contemporary DirectionsSeveral developments are influencing application modernization. Platform engineering teams increasingly provide internal platforms that package deployment, security, observability, policy, and developer workflows. This can reduce cognitive load, but a platform becomes harmful when it imposes abstractions that conceal important operational behavior. Managed messaging, databases, API gateways, and serverless functions allow teams to consume capabilities without operating every component. The trade-off is increased dependence on provider interfaces, pricing models, regional availability, and service limits. Architects must evaluate portability according to actual strategic needs rather than treating portability as an absolute goal. Progressive delivery techniques such as canary releases, blue-green deployment, feature flags, and automated rollback support incremental modernization. Observability is becoming more analytical through trace-based dependency mapping, anomaly detection, and automated correlation of logs, metrics, and traces. Artificial intelligence can assist with code analysis, test generation, dependency discovery, and incident investigation, but generated changes require review, security assessment, and domain validation. AI does not remove the need for architectural judgment. Best-Practice GuidanceA sound modernization program generally follows these principles: - Start with business capabilities and measurable outcomes, not preferred technologies.
- Use domain language to discover boundaries and make conflicting meanings visible.
- Prefer a modular monolith when distributed deployment is not yet justified.
- Give each service or module clear ownership of responsibilities and data.
- Design contracts for compatibility, observability, security, and failure.
- Treat retries, duplicates, timeouts, and partial failure as normal possibilities.
- Introduce asynchronous messaging where temporal decoupling creates real value.
- Use sidecars and service meshes selectively, with explicit resource and failure analysis.
- Migrate incrementally, retaining rollback and reconciliation mechanisms.
- Delete obsolete paths after successful migration; otherwise complexity accumulates.
- Measure outcomes in business and operational terms rather than counting services.
- Align architecture with team capabilities, governance, compliance, and support responsibilities.
Chapter SummaryApplication architecture determines how business responsibilities, data, communication, deployment, and operational concerns are organized. Microservices can provide independent deployment and scaling, but they also introduce distributed-systems complexity. A modular monolith is often a stronger starting point when boundaries or operational capabilities are immature. Domain-driven design helps identify subdomains, bounded contexts, ubiquitous language, aggregates, and relationships among contexts. APIs support explicit contracts, while messaging and event-driven architecture provide temporal decoupling at the cost of eventual consistency, duplication, schema, and observability challenges. The transactional outbox and saga patterns address important coordination problems. Sidecars separate selected platform capabilities from application code but should be adopted deliberately. Twelve-factor principles provide a practical assessment of configuration, dependencies, process behavior, deployment, logs, and operational tasks. Legacy modernization should begin with business objectives and may involve retaining, rehosting, replatforming, refactoring, rearchitecting, or replacing systems. The strangler pattern enables incremental migration through façades, controlled routing, explicit data ownership, reconciliation, and retirement of obsolete paths. Successful modernization combines technical design with organizational ownership, security, governance, measurement, and professional judgment. Key TermsApplication architecture: The significant structures, responsibilities, interactions, and constraints of a software system. Modular monolith: A single deployable application organized into explicit, internally decoupled modules. Microservices: Independently deployable services organized around business capabilities. Bounded context: A boundary within which a domain model and terminology have consistent meaning. Ubiquitous language: Shared domain vocabulary used consistently by experts, developers, code, and documentation. Aggregate: A domain consistency boundary controlled through an aggregate root. Anti-corruption layer: A translation boundary that prevents one domain model from inheriting another model’s assumptions. API: A defined interface through which software components exchange capabilities or information. Idempotency: The property that repeating an operation produces the same intended effect as performing it once. Message broker: Infrastructure that receives, routes, stores, and delivers messages between producers and consumers. Event: A record of a business or system fact that has occurred. Command: A request for a component to perform an action. Eventual consistency: A consistency model in which replicas or consumers converge after a delay rather than immediately. Transactional outbox: A pattern that stores a business change and its outgoing event in the same local transaction. Saga: A sequence of local transactions coordinated with compensating actions when later steps fail. Sidecar: A supporting process deployed alongside an application process to provide auxiliary capabilities. Twelve-factor application: An application designed according to principles supporting portable, configurable, independently deployable operation. Strangler pattern: An incremental modernization approach in which new capabilities progressively replace legacy paths. Rehosting: Moving an application to a new infrastructure environment with minimal code change. Progressive delivery: Controlled release of changes through techniques such as canaries, feature flags, and staged rollout. Review QuestionsShort Answer Questions1. What distinguishes a modular monolith from a microservices architecture? 2. Define a bounded context and explain why it is useful in application design. 3. What is the difference between an event and a command? 4. Why is idempotency important in distributed systems? 5. State four twelve-factor principles relevant to Kubernetes applications. Long Answer Questions1. Explain how domain-driven design can guide the decomposition of a complex application. Include bounded contexts, ubiquitous language, aggregates, and anti-corruption layers. 2. Compare synchronous APIs and asynchronous messaging with respect to coupling, failure, consistency, and operational complexity. 3. Discuss the benefits and limitations of modular monoliths and microservices. Recommend conditions under which each should be selected. 4. Explain the transactional outbox and saga patterns and the problems they address. 5. Describe a complete strangler-pattern modernization strategy, including traffic migration, data ownership, observability, rollback, and retirement. Analytical / Application Questions1. A proposed architecture separates an application into six services, but all services update the same database tables and must be released together. Analyze the design and recommend a more suitable alternative. 2. An order service publishes an `OrderConfirmed` event, but consumers occasionally receive it twice. Design controls that preserve correct business behavior without requiring exactly-once delivery. 3. A legacy claims system has tightly coupled customer, policy, and payment functions. Select an initial modernization slice and justify your choice using domain boundaries, risk, data ownership, and business value. 22. Multiple Choice Questions with AnswersQuestion 1Which condition most strongly supports choosing a modular monolith rather than immediately adopting microservices? A. The application requires many independently scaling workloads B. The domain is poorly understood and transactional coupling is high C. Different teams must use unrelated technology stacks D. Every capability requires independent failure isolation Correct Answer: B. The domain is poorly understood and transactional coupling is high Question 2What is the primary purpose of a bounded context in domain-driven design? A. To define the physical size of a Kubernetes Pod B. To guarantee that every domain uses one universal data model C. To establish where a model and its terminology have consistent meaning D. To replace all APIs with database access Correct Answer: C. To establish where a model and its terminology have consistent meaning Question 3A client retries a payment request after receiving a timeout. Which design property most directly prevents an unintended duplicate payment? A. Idempotency B. Horizontal scaling C. Port binding D. Log aggregation Correct Answer: A. Idempotency Question 4Which statement best describes the transactional outbox pattern? A. It stores all application data in a message broker B. It writes a business change and an outgoing event in one local transaction C. It guarantees that every message is delivered exactly once D. It eliminates the need for consumer error handling Correct Answer: B. It writes a business change and an outgoing event in one local transaction Question 5Which interaction is most appropriate for asynchronous messaging? A. A user must immediately know whether a password is valid B. An order confirmation triggers independent notification processing C. A service must synchronously validate a required inventory reservation D. A client requests a current account balance for display Correct Answer: B. An order confirmation triggers independent notification processing Question 6What is a principal risk of adding automatic retries at several sidecar and application layers? A. The service can no longer expose a network port B. Retries may amplify load during dependency failure C. The application becomes incapable of structured logging D. The database becomes automatically schema-free Correct Answer: B. Retries may amplify load during dependency failure Question 7In a strangler migration, what is the purpose of an anti-corruption layer? A. To prevent all communication between old and new systems B. To translate legacy representations without importing their assumptions into the new model C. To encrypt every database backup automatically D. To ensure that the legacy system remains the permanent system of record Correct Answer: B. To translate legacy representations without importing their assumptions into the new model Question 8Which modernization strategy changes infrastructure while making minimal application changes? A. Rehosting B. Rebuilding C. Rearchitecting D. Replacing Correct Answer: A. Rehosting Question 9A consumer processes the same event twice. Which approach is most appropriate? A. Assume the broker will never duplicate messages B. Make the consumer idempotent and record processed operation identifiers C. Disable all retries in the producer D. Require every consumer to share the producer’s database Correct Answer: B. Make the consumer idempotent and record processed operation identifiers Question 10Which statement accurately characterizes Kubernetes in application modernization? A. Kubernetes automatically discovers correct business-service boundaries B. Kubernetes replaces the need for domain modeling C. Kubernetes provides operational capabilities but does not by itself create a sound application architecture D. Kubernetes guarantees distributed transaction consistency Correct Answer: C. Kubernetes provides operational capabilities but does not by itself create a sound application architecture
|