In software engineering, an Architectural Pattern is a general and reusable solution to an occurring problem in a particular context. It is a recurring solution to a recurring problem.
The purpose of Architectural Patterns is to understand how the major parts of the system fit together and how messages and data flow through the system. You can have multiple patterns in a single system to optimize each section of your code.
As much terminology in Software Development, these terms are not clear and different people give it a different meaning. MSDN says that Architectural Styles and Architectural Patterns are the same things, but personally, I prefer to think of these in the lines of what is explained by George Fairbanks and Michael Keeling.
It is also important to reinforce the idea that Architectural Styles, Architectural Patterns and Design Patterns are not mutually exclusive, they are complementary and they all can teach us something, although, as usual, they should be used only when needed.
Through this article, we are going to take a look at what we call Architectural Patterns, Architectural Styles and Design Patterns.
Architectural styles tell us, in very broad strokes, how to organize our code. It’s the highest level of granularity and it specifies layers, high-level modules of the application and how those modules and layers interact with each other, the relations between them. Examples of Architectural Styles:
- Monolithic application
- Pipes and filters
An Architectural Style can be implemented in various ways, with a specific technical environment, specific policies, frameworks or practices.
A pattern is a recurring solution to a recurring problem. In the case of Architectural Patterns, they solve the problems related to the Architectural Style. For example, “what classes will we have and how will they interact, in order to implement a system with a specific set of layers”, or “what high-level modules will have in our Service-Oriented Architecture and how will they communicate”, or “how many tiers will our Client-server Architecture have”.
Architectural Patterns have an extensive impact on the code base, most often impacting the whole application either horizontally (i.e. how to structure the code inside a layer) or vertically (i.e. how a request is processed from the outer layers into the inner layers and back). Examples of Architectural Patterns:
Design Patterns differ from Architectural Patterns in their scope, they are more localized, they have less impact on the code base, they impact a specific section of the code base, for example:
- How to instantiate an object when we only know what type needs to be instantiated at run time (maybe a Factory Class?);
- How to make an object behave differently according to its state (maybe a state machine, or a Strategy Pattern?).
Some major Architectural Patterns and Architectural Patterns Styles
Knowing what we know, let’s now have a brief overview of some major Architectural Patterns and Architectural Styles.
This pattern is used to structure programs that can be decomposed into groups of subtasks. It partitions the concerns of the application into layers.
Most of the time, we have four layers:
- Presentation layer or UI layer
- Application layer or Service layer
- Business logic layer or Domain layer
- Data access layer or Persistence layer
The popular Model-View-Controller structure (MVC) is a Layered architecture. The Model layer is just above the database and it sometimes contains some business logic. The View is the top layer and corresponds to what the final user sees. The Controller layer is in the middle and it is in charge to send data from the Model to the View and vice versa.
One major advantage of this pattern is the separation of concerns. It means that each layer focuses only on its role.
Also called EDA, this pattern organizes a system around the production, detection and consumption of events. Such a system consists of event Emitters and event Consumers. Emitters are decoupled from Consumers, which are also decoupled from each other.
An Emitter is an event source and only knows that the event has occurred. A Consumer needs to know an event has occurred and it has the responsibility of applying a reaction as soon as an event is presented. Sometimes, the reaction is not completely provided by a single Consumer that might forward the event to another component after it has filtered or transformed it.
Consumers can subscribe to an event manager receives notifications when events are emitted and forward events to all registered Consumers.
Event-driven architecture is easily adaptable to complex environments and can be easily extended when new event types appear. On the other hand, testing can be complex because interactions between modules can only be tested in a fully functioning system.
That kind of architecture is often used for asynchronous systems or user interfaces.
Domain Driven Design
This Architectural Style, also known has DDD, is an object-oriented approach. Here, the idea is to design software based on the Business Domain, its elements and behaviors, and the relationships between them.
The Business Domain is like a sphere of knowledge and activity around which the application logic revolves. It involves rules, processes and existing systems that need to be integrated into our solution. It is a set of classes that represent objects in the Business Model being implemented. The Business Model is the solution to the problem we are trying to solve. To organize and structure the knowledge of our problem, we use a Domain Model that should be accessible and understandable by everyone who is involved with the project. Domain Driven Design is about solving the problems of an organization. The Domain Model is about understanding and interpreting the important aspects of the given problems.
A language is also structured around the Domain Model and used by all team members to connect all the activities of the team with the software. It is called Ubiquitous Language. We also refer to the Context to define the setting that determines the meaning of a statement.
Domain Driven Design eases communication and improves flexibility.
Domain Driven Design is useful when we build complex software where the need for change is determined. We have to be careful and remember that DDD is not about how to code, but it is a way of looking at things.
Pipes and Filters
This Architectural Style decomposes a task that performs complex processing into a series of separate elements that can be reused. In other words, it consists of any number of components, called Filters, that transform or filter data, before passing it to other components through connectors called Pipes.
A Filter transforms the data it receives through Pipes with which it is connected. A Filter can have many input Pipes and many output Pipes.
A Pipe is some kind of connector that passes data from one Filter to the next.
There are also two other components, the Pump, which is the data source, and the Sink, which is the final target.
Pipes and Filters can be applied when the processing of our application can be broken down into a set of independent steps. It can also be useful when flexibility is required or when each step of the processing of the application have different scalability requirements.
The goal of a Microservices architecture is, instead of building one single big monolithic application, to create several tiny programs.
Such an architecture requires every service to be completely independent of the others.
This architecture can be helpful when we want to develop new businesses or web applications rapidly.
Through this article we saw what Architectural Patterns are. We compared them to Architectural Styles and Design Patterns to understand the differences. We also had a brief overview of some major Architectural Patterns and Styles.
As I mentioned in the beginning of this post, it’s all about the scope:
- An Architectural Style is the application design at the highest level of abstraction;
- An Architectural Pattern is a way to implement an Architectural Style;
- A Design Pattern is a way to solve a localized problem.
Furthermore, a pattern might be able to be used both as an Architectural Pattern or a Design Pattern, again depending on the scope we use it in, in a specific project.