Architecture Styles and Design Patterns
1. Overview
A. Definition
An architecture style is a macro-level design framework that organizes the overall structure of a system, whereas a design pattern is a micro-level, reusable solution that repeatedly solves a specific design problem. The former prescribes the placement and connection of components and their quality attributes; the latter prescribes creation, structure, and behavior at the class and object level.
The relationship between the two concepts becomes clear when compared to a building's structural style versus formalized techniques for decorating a room. If the architecture style determines the overall skeleton of the building—whether it is an apartment or a detached house (layered, MSA, event-driven, etc.)—then design patterns are proven ways to solve local problems that are encountered repeatedly inside that building, such as "how do I create and share only a single instance of a particular object." Changing the style of a building is close to redoing the work from the foundation up, but changing the technique for arranging furniture in a room is relatively local and easy to reverse.
The essential difference between the two lies in abstraction level and scope of impact. The choice of architecture style is an irreversible decision that determines system-wide quality attributes such as performance, scalability, availability, and security. A design pattern, by contrast, deals with flexibility and reusability at the level of a specific class or component, so it can be replaced relatively easily through refactoring. This is also the context in which Martin Fowler described "architecture as the set of decisions that are hard to reverse."
B. Background and Necessity
The larger and more complex software becomes, the more inefficient and failure-prone it is to reconsider the structure from scratch every time. Since the so-called "software crisis" of the late 1960s, efforts to reuse proven structural solutions have accumulated. Architecture styles were systematized by David Garlan and Mary Shaw in the 1990s, and design patterns were formalized as 23 patterns in 1994 by the Gang of Four (GoF) in their book Design Patterns: Elements of Reusable Object-Oriented Software.
There are three reasons why these two tools are needed. First, reusability—reusing solutions that senior developers have validated through trial and error, so as not to reinvent the wheel. Second, communication—compressing and conveying design intent through a shared vocabulary such as "this part is the Observer pattern" or "the whole is MSA." Third, quality predictability—since a proven structure is known for which quality attributes it gains and what it sacrifices, trade-offs can be judged in advance.
2. The Overall Landscape of Architecture Styles and Design Patterns
The two concepts occupy different layers within a single system. The conceptual diagram below shows how the macro (style) and the micro (pattern) work together hierarchically.
flowchart TB
subgraph MACRO["Macro · whole system (Architecture Style)"]
L["Layered"]
M["Microservices (MSA)"]
E["Event-driven"]
end
subgraph MICRO["Micro · inside a component (Design Pattern)"]
C["Creational"]
ST["Structural"]
B["Behavioral"]
end
MACRO -->|"set the structural skeleton, then fill the inside"| MICRO
QA["Quality attributes (performance·scaling·security)"] --- MACRO
RU["Code reuse·flexibility"] --- MICRO
style MACRO fill:#e8f0fe,stroke:#2f6fed,stroke-width:2px
style MICRO fill:#fef3e8,stroke:#ed8a2f,stroke-width:2px
The point emphasized in the figure above is that the two layers are in a complementary rather than competitive relationship. Once the architecture style sets the system's skeleton and component boundaries, the inside of each component is implemented with design patterns. For example, in an MSA, the payment module inside each microservice can switch payment methods with the Strategy pattern, create payment objects with the Factory pattern, and notify payment-completion events with the Observer pattern.
The difference between the two concepts, organized from a practical perspective, is as follows. The table is an aid to comparison; the key is "why that difference arises." Because their scope differs, the ripple effect of a change differs, and because the ripple of a change differs, the difficulty of reversing it differs.
| Category | Architecture Style | Design Pattern |
|---|---|---|
| Scope | Whole system (macro) | Class·component (micro) |
| Concern | Structure·components·connections·quality attributes | Object creation·structure·behavior |
| Impact | Performance·scaling·security (hard to reverse) | Code reuse·flexibility (easy to replace) |
| Representative artifact | Architecture specification·C4 diagram | Class diagram·UML |
| Examples | Layered, MSA, event-driven, pipe-filter | Singleton, Factory, Observer, Strategy |
3. Representative Architecture Styles
Architecture styles are chosen according to the problem domain and quality requirements. Here, the three most frequently used in practice—layered, microservices, and event-driven—are covered in detail, down to their principles and trade-offs.
flowchart TB
S["Choosing an architecture style"] --> L["Layered<br/>simple·universal"]
S --> M["Microservices (MSA)<br/>scalable·autonomous"]
S --> E["Event-driven<br/>real-time·asynchronous"]
L --> LT["Trade-off: vulnerable to sinkhole changes"]
M --> MT["Trade-off: distributed complexity"]
E --> ET["Trade-off: hard to trace flow"]
style S fill:#e8f0fe,stroke:#2f6fed,stroke-width:2px
A. Layered Architecture
The layered style horizontally separates a system into presentation, business, and data-access layers to divide concerns, and it is the most universal and easiest-to-understand style. In principle, each layer depends only on the layer directly below it in a one-directional flow, and thanks to this rule, an internal change in a particular layer does not propagate to other layers. For example, even if you change the data-access technology from MyBatis to JPA, the business layer is unaffected as long as it keeps the same interface.
The strength of this style is its low learning cost and clear separation of responsibilities. This is why most enterprise web applications (the traditional Spring MVC 3-tier structure) adopt it. But its limitations are also clear. When it becomes frequent for a single requirement change to cut through the presentation, business, and data layers all at once (a sinkhole)—for instance, when adding a single field requires modifying the screen, service, DTO, entity, and table all together—the benefits of layer separation are nullified. Also, since every request passes through the layers sequentially, in large-scale services with surging traffic the unit of scale-out becomes the entire application, which is inefficient.
In practice, it suits places where the domain rules are simple and the lifespan is predictable, such as in-house administrative systems, or where fast development matters, such as an early startup's MVP. Conversely, in large commerce where traffic and domain complexity grow together, it is hard to hold up with the layered style alone, and it often evolves into MSA.
B. Microservices (MSA) Architecture
Microservices is a style that decomposes a system into small, independently deployable services. Each service owns its own database (Database per Service), and services communicate with each other via REST, gRPC, or messaging. Netflix is a representative case: over roughly seven years starting in 2009, it transformed its monolith into more than 700 microservices, handling millions of requests per second, and Amazon, Uber, and Coupang have followed similar paths.
MSA has three core benefits. First, independent deployment—the payment service alone can be deployed dozens of times a day, so deployment risk is isolated. Second, per-service scaling—only the product-lookup service that traffic pours into has its instances increased, using resources efficiently. Third, fault isolation—even if the recommendation service dies, the order service can keep working, and a circuit breaker can cut it off.
But the price of these benefits is the intrinsic complexity of distributed systems. The network is unreliable (latency and disconnection), data consistency spanning multiple services must be solved with the Saga pattern and eventual consistency instead of distributed transactions, and additional observability infrastructure and a service mesh are needed for logging, tracing, and monitoring. In other words, development complexity is transferred into operational complexity. This is why Martin Fowler warned that "to take on MSA you must first attain a minimum level of maturity (deployment automation, monitoring, incident response)."
Below is a detailed diagram of the flow by which a user's order request is processed in an MSA environment.
sequenceDiagram
participant U as User
participant G as API Gateway
participant O as Order Service
participant P as Payment Service
participant I as Inventory Service
participant Q as Message Broker
U->>G: Order request
G->>O: Routing
O->>P: Payment authorization request
P-->>O: Authorization complete
O->>Q: Publish order-created event
Q->>I: Subscribe to stock deduction
I-->>Q: Stock confirmation event
O-->>U: Order accepted response
C. Event-Driven Architecture
Event-driven is a style in which a component publishes a state change as an "event" and interested components subscribe to it and react. Since publishers and subscribers do not directly know one another, loose coupling is maximized, and asynchronous processing yields real-time responsiveness and scalability. Event streaming centered on Apache Kafka is a representative implementation, and it demonstrates its power in places that handle hundreds of thousands of events per second, such as real-time recommendation, IoT sensor processing, and financial-transaction audit logs.
The strengths of this style are scalability and evolvability. Adding a new subscriber (e.g., a marketing analytics service) requires no modification of the publisher's code, so the system can be extended incrementally. On the other hand, since the flow spreads asynchronously through many events, it is hard to trace and debug the whole processing flow at a glance, and event ordering, duplicate processing (idempotency), and eventual consistency must be designed separately. To grasp "how far it was processed" when a failure occurs, distributed tracing becomes essential.
Comparing the trade-offs of the three styles, the selection criterion ultimately lies in the required quality attributes. If simplicity is the priority, the layered style; if independent scaling and autonomous development are the priority, MSA; if real-time responsiveness and loose coupling are the priority, event-driven.
| Style | Core Strength | Trade-off | Representative Application |
|---|---|---|---|
| Layered | Simple·clear separation of responsibilities | Vulnerable to sinkhole changes, unit of scaling is the whole | In-house admin system, MVP |
| Microservices | Independent deployment·scaling·fault isolation | Distributed complexity·operational burden | Netflix, large commerce |
| Event-driven | Loose coupling, real-time·asynchronous | Hard to trace flow·order·duplicate processing | Real-time recommendation, IoT, finance |
4. GoF Design Patterns
GoF design patterns are divided into three types by purpose. Creational patterns encapsulate how objects are created, separating creation logic from usage logic; structural patterns deal with how objects and classes are composed to form larger structures; and behavioral patterns deal with the distribution of responsibilities among objects and their interaction and communication. Underlying this classification are the encapsulation principle "separate what varies from what does not vary" and the SOLID design principles.
flowchart TB
G["23 GoF patterns"] --> CR["Creational (5)<br/>encapsulate object creation"]
G --> STR["Structural (7)<br/>compose objects·classes"]
G --> BEH["Behavioral (11)<br/>distribute responsibility·interaction"]
CR --> C1["Singleton·Factory Method<br/>Abstract Factory·Builder·Prototype"]
STR --> S1["Adapter·Decorator·Proxy<br/>Facade·Composite·Bridge·Flyweight"]
BEH --> B1["Observer·Strategy·Command·State<br/>Iterator·Template Method·Chain of Responsibility"]
style G fill:#fef3e8,stroke:#ed8a2f,stroke-width:2px
A. Creational Patterns
The core motivation of creational patterns is "to keep the code that uses an object from being shaken when the way that object is created changes." The Singleton creates and shares only a single instance, and is used for resources that need to exist globally in exactly one copy, such as configuration, logging, and connection pools. However, since it creates global state, making testing difficult and incurring synchronization costs in a multithreaded environment, in modern practice a DI container (Spring's Bean scope) often takes over singleton management.
The Factory Method delegates object creation to subclasses, lowering the coupling between the client and concrete classes. Even when a new type is added, only the factory needs to be extended rather than the client code, so it supports the Open-Closed Principle (OCP). The Builder assembles an object step by step when constructor arguments are many and optional, improving readability and immutability (e.g., Java's StringBuilder, the Builder APIs of various SDKs).
B. Structural Patterns
Structural patterns focus on composing already-existing classes and objects to create new functionality or interfaces without modifying the existing code. The Adapter converts incompatible interfaces to connect them—it is essential when fitting a legacy system or external library to new code, and it is directly connected to the "adapter" concept of hexagonal architecture. The Decorator dynamically layers functionality onto an object through composition instead of inheritance (e.g., Java I/O streams' BufferedReader(new FileReader(...))). The Proxy has a surrogate object control access to the real object, transparently handling lazy loading, access control, caching, and remote invocation (e.g., JPA's lazy-loading proxy, RPC stubs).
C. Behavioral Patterns
Behavioral patterns deal with how responsibilities are divided among objects and how they communicate. The Observer automatically notifies subscribers of a state change in one object (the Subject), implementing publish-subscribe at the code level, and it is the basis for the model-view refresh in MVC and for event listeners. Interestingly, the Observer pattern can be seen as a micro version of the event-driven architecture seen earlier, showing that a style and a pattern are the same principle at different scales. The Strategy encapsulates a family of algorithms individually so they can be swapped at runtime—it is used when "what to do is the same but the method differs," such as payment methods (card, bank account, easy payment) or sorting and discount policies. The Command encapsulates a request as an object, enabling execution, undo, queuing, and logging.
| Type | Purpose | Representative Patterns | Practical Example |
|---|---|---|---|
| Creational | Encapsulate object creation | Singleton, Factory Method, Builder | DI container, SDK Builder |
| Structural | Compose objects·classes | Adapter, Decorator, Proxy | I/O streams, JPA lazy loading |
| Behavioral | Distribute responsibility·interaction | Observer, Strategy, Command | MVC, payment strategy, Undo |
5. In-Depth: Distributed Architecture Patterns in the Cloud-Native Era
Whereas traditional GoF patterns deal with object-level problems within a single process, the MSA and cloud-native environment demands a new class of patterns that "span processes and networks." This does not replace GoF but complements it at a higher scale.
First, the Circuit Breaker is a pattern popularized by Netflix Hystrix (now Resilience4j) that prevents cascading failure of downstream services. When the call failure rate exceeds a threshold, it "opens" the circuit and immediately returns a failure response, and after a set time it sends a trial call in a "half-open" state to check for recovery. This physically blocks a failure from spreading throughout the entire system.
Second, the Saga is a pattern that replaces distributed transactions in MSA. It divides work spanning multiple services into a chain of local transactions, and if a step fails midway, it executes a compensating transaction that undoes the steps already performed. There are the orchestration (a central coordinator) approach and the choreography (a chain of events) approach, and it guarantees eventual consistency in work that traverses multiple services, such as order-payment-shipping.
Third, the API Gateway and BFF (Backend for Frontend) handle authentication, routing, aggregation, and rate limiting at a single entry point between the client and many microservices. Fourth, CQRS and Event Sourcing separate the command (write) and query (read) models and store state as an accumulation of events, providing read scaling and complete audit tracing.
From the perspective of past-question linkage, the Professional Engineer Information Management exam has posed architecture styles (layered, MSA, event-driven) and the GoF classification, and more recently MSA migration strategies, circuit breakers, and Sagas, either standalone or in case form. Therefore, an answer can simultaneously demonstrate depth and currency if it is developed in the hierarchical composition "difference between style and pattern → trade-offs of representative styles → the three GoF categories → expansion into cloud-native patterns."
6. Considerations and Implications
Architecture styles secure quality attributes; design patterns secure code flexibility. Since the two layers differ in purpose and scope of impact, they should be applied complementarily rather than competitively. Piling up patterns while deferring the style decision results in mere local optimization, and setting the style without patterns raises coupling at the implementation stage.
Overuse of patterns is over-engineering. Applying "patterns for patterns' sake" where there is no problem only adds complexity. Following the YAGNI (You Aren't Gonna Need It) principle, apply them sparingly only where change is actually anticipated, and first verify whether a real reason for change (an axis of change) exists.
Because architecture is a decision that is hard to reverse, judge trade-offs explicitly. MSA presupposes organizational maturity in deployment automation, monitoring, and incident response, and adopting it without that maturity produces the worst outcome—a "distributed monolith." As with Conway's Law, the alignment between organizational structure and architecture must also be considered together.
In the cloud-native and MSA era, distributed patterns that complement traditional GoF are essential. One must understand the Circuit Breaker, Saga, CQRS, Event Sourcing, and the like, and include the operational perspective in the design by combining them with observability (logs, metrics, tracing), a service mesh (e.g., Istio), and container orchestration (Kubernetes).
A strategic choice from the professional engineer's perspective. Styles and patterns are not a silver bullet; choose by synthesizing business requirements, team capability, expected lifespan, and traffic characteristics. Starting simply with a monolith at first and evolving incrementally into MSA or event-driven when the need becomes clear (the Strangler Fig pattern) is the practical strategy that lowers risk.
References
- Erich Gamma et al., Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley, 1994.
- Martin Fowler, "Microservices", https://martinfowler.com/articles/microservices.html
- Chris Richardson, "Microservices Patterns", https://microservices.io/patterns/index.html
- Refactoring.Guru, "Design Patterns", https://refactoring.guru/design-patterns
- Microsoft, "Cloud Design Patterns", https://learn.microsoft.com/en-us/azure/architecture/patterns/
In one line: Architecture styles (layered, MSA, event-driven) are macro-level, hard-to-reverse frameworks that determine a system's overall structure and quality attributes, while GoF design patterns (creational, structural, behavioral) are micro-level solutions to recurring design problems; in the cloud-native era, distributed patterns such as the circuit breaker and Saga complement them, so trade-offs must be judged explicitly and applied sparingly and complementarily.