Software Engineering Mastery
Architectural Patterns
Architectural Patterns
Think of an architectural pattern as a high-level blueprint for a software system. It’s not about the small details of how a single button works, but about the overall structure. How are the major pieces of the application organized? How do they communicate? Choosing the right pattern is a critical early decision, as it sets the foundation for how the system will be built, maintained, and scaled over time.
An architectural pattern is a reusable solution to a common problem in software architecture.
The Layered Approach
One of the most traditional and straightforward patterns is the layered architecture. Imagine a building with three floors. The top floor is the user interface—what the user sees and interacts with. The middle floor contains the business logic, where all the thinking and processing happens. The ground floor is the data layer, responsible for storing and retrieving information.
Each layer has a specific job and can only communicate directly with the layers immediately above or below it. This separation of concerns makes the system easier to develop and maintain. A developer working on the user interface doesn't need to know the details of how data is stored, and vice versa.
This pattern is great for many standard applications. However, as the application grows, the whole structure is still a single unit, often called a monolith. Making a small change in one layer might require redeploying the entire application, which can become slow and risky.
Breaking Down the Monolith
When a single, layered application becomes too large and complex, architects often look for ways to break it into smaller, more manageable pieces. This leads to service-based approaches.
Service-Oriented Architecture (SOA) was an early approach to this. In SOA, the application is composed of distinct services that represent business functions, like 'Process Payment' or 'Check Inventory'. These services are often large and communicate through a central messaging system called an Enterprise Service Bus (ESB). The ESB acts like a post office, routing messages between the correct services.
Microservices Architecture is a more modern refinement of SOA. Instead of large, enterprise-wide services, a microservices application is broken down into many small, independent services. Each service is built around a specific business capability, like 'User Management' or 'Product Catalog'.
Unlike SOA, these services don't rely on a central bus. They communicate directly with each other using lightweight mechanisms like APIs. Each microservice can be developed, deployed, and scaled independently. This autonomy allows teams to work in parallel and release updates much faster.
If you can't build a monolith successfully, you're not ready for microservices. The complexity of a system doesn't disappear; it just moves from inside the application to the network connections between services.
As systems become collections of independent services, communication becomes a key challenge. How do services notify each other when something important happens?
Event-Driven Architecture (EDA) provides an answer. In this pattern, services communicate by producing and consuming events. An event is a notification that something significant occurred. For example, when a customer places an order, the 'Order Service' might publish an 'OrderPlaced' event. Other services, like 'Inventory Service' and 'Notification Service', can subscribe to this event and react accordingly. The 'Inventory Service' would update stock levels, and the 'Notification Service' would send a confirmation email.
This approach decouples services from each other. The 'Order Service' doesn't need to know which other services care about a new order; it just announces the event. This makes the system highly scalable and resilient. If the 'Notification Service' is temporarily down, it can process the events later once it's back online, without affecting the order process itself.
Organizing by Domain
Regardless of whether you use a monolith or microservices, you need a way to organize your code that reflects the business itself. This is the core idea behind Domain-Driven Design (DDD).
DDD is not an architectural pattern in the same way as the others, but rather a strategic approach to designing complex software. It emphasizes collaboration between technical developers and business domain experts to model the software around the business's core concepts and processes.
Ubiquitous Language
noun
A common, shared language developed by the team (developers, domain experts, stakeholders) to talk about the software and the business domain it represents.
A key concept in DDD is the Bounded Context. This is a boundary within which a particular domain model is defined and consistent. For example, the meaning of 'Customer' might be different in the 'Sales' context versus the 'Support' context. In Sales, a customer has a credit limit. In Support, a customer has a history of support tickets. A Bounded Context creates a clear line where the model for 'Customer' changes.
This approach is a natural fit for microservices, where each microservice can be designed as its own Bounded Context, with its own model and its own Ubiquitous Language.
What is a primary drawback of a layered (monolithic) architecture, especially as the application grows larger?
In a Microservices Architecture, services are typically large and communicate through a central messaging system called an Enterprise Service Bus (ESB).

