[Treasure Series] 7 Architectural Patterns for Embedded Software Design

Table of Contents

  • Preface
  • 1️⃣ Layered Architecture
  • 2️⃣ Multi-tier Architecture
  • 3️⃣ Pipe and Filter Architecture
  • 4️⃣ Client-Server Architecture
  • 5️⃣ Model-View-Controller Architecture (MVC)
  • 6️⃣ Event-driven Architecture
  • 7️⃣ Microservices Architecture

Preface

Architectural patterns, also known as architectural styles, are general, reusable solutions to common problems in software architecture within a given context. Similar to software design patterns, but broader in scope, they address various issues in software engineering, such as hardware performance limitations, high availability, and minimizing business risks.
In embedded software design, there are mainly the following 7 architectural patterns:

  1. Layered Architecture
  2. Multi-tier Architecture
  3. Pipe and Filter Architecture
  4. Client-Server Architecture
  5. Model-View-Controller Architecture
  6. Event-driven Architecture
  7. Microservices Architecture

1️⃣ Layered Architecture

The most common architectural pattern is the layered architecture, also known as n-tier architecture.
Most software architects, designers, and developers are very familiar with this pattern. Although there are no specific restrictions on the number and types of layers, most layered architectures consist of four layers: presentation layer, business layer, persistence layer, and database layer, as shown in the figure below.
Insert image description here

1. Context
All complex systems need to independently develop and evolve their various parts. For this reason, system developers need to have a clear and well-organized separation of concerns so that each module of the system can be developed and maintained independently.

2. Problem
The software needs to be divided in such a way that each module can be developed and evolved independently, with minimal interaction between the parts, supporting portability, modifiability, and reusability.

3. Solution
To achieve separation of concerns, the layered pattern divides the software into units (called "layers"). Each layer is a set of modules that provides a set of highly cohesive services. Its use must be unidirectional. Layers partition the software into complete sections, each exposing a public interface.

  • The first concept is that each layer has a specific role and responsibility. For example, the presentation layer is responsible for handling all user interfaces. This separation of concerns in layered architecture makes it easy to build efficient roles and responsibilities.
  • The second concept is that the layered architecture pattern is a technical partitioning architecture, not a domain partitioning architecture. They are composed of components, not domains.
  • The final concept is that each layer in a layered architecture is marked as closed or open. A closed layer means that a request moving from one layer to another must pass through the layer immediately below it to reach the layer below that. Requests cannot skip any layers.

4. Weaknesses
Layering can lead to performance degradation. This pattern is not suitable for high-performance applications because it is inefficient to implement a business request through multiple layers in the architecture.
Layering also increases the upfront cost and complexity of the system.

5. Uses
This approach should be applied to small, simple applications or websites. It is a good choice for scenarios with tight budgets and timelines.

2️⃣ Multi-tier Architecture

The execution structure of many systems is organized into a series of logical component groups. Each group is called a tier.

1. Context
In a distributed deployment, it is often necessary to divide the system's infrastructure into different subsets.

2. Problem
How do we partition the system into multiple computationally independent execution structures: software and hardware groups connected by some communication medium?

3. Weaknesses
High upfront costs and complexity.

4. Uses
Used in distributed systems.

3️⃣ Pipe and Filter Architecture

A recurring pattern in software architecture is the pipe-filter pattern.
1. Context
Many systems need to transform discrete data streams from input to output. Many types of transformations recur in practice, so it is ideal to create them as independent, reusable parts.

2. Problem
These systems need to be divided into reusable, loosely coupled components with simple, general interaction mechanisms so that they can be flexibly combined. These general, loosely coupled components are easy to reuse. The independent components can be executed in parallel.

3. Solution
In this architecture, pipes form the communication channels between filters. The first concept is that, for performance reasons, each pipe is non-directional and point-to-point, accepting input from one source and often directly outputting to another source.
In this pattern, there are four types of filters:

  • Producer (source): The starting point of a process.
  • Transformer (map): Transforms some or all of the data.
  • Tester (reduce): Tests one or more conditions.
  • Consumer (sink): The endpoint.

4. Weaknesses
Not very suitable for interactive systems due to their transformational nature.
Excessive parsing and unparsing can lead to performance loss and increase the complexity of writing the filters themselves.

5. Uses
The pipe-filter architecture is used in various applications, especially for simplifying single-processing tasks, such as EDI and ETL tools.
Compilers: Sequential filters perform lexical analysis, parsing, semantic analysis, and code generation.

4️⃣ Client-Server Architecture

1. Context
There are many shared resources and services that a large number of distributed clients wish to access, and we want to control access or service quality.

2. Problem
By managing a set of shared resources and services, we can improve modifiability and reusability by decomposing public services and modifying them in a single location or a few locations. We want to improve scalability and availability by centralizing control over these resources and services while distributing the resources themselves across multiple physical servers.

3. Solution
In the client-server pattern, components and connectors have specific behaviors.

Components called "clients" send requests to components called "servers" and then wait for a reply.
Server components receive requests from clients and send replies to them.

4. Weaknesses
Servers can become performance bottlenecks and single points of failure.

Decisions about the location of functionality (on the client or server) are often complex and costly to change after the system is built.

5. Uses

For systems with many components (clients) sending requests to other components (servers) that provide services, we can use the client-server pattern to model part of the system: online applications, such as email, shared documents, or banking services.

5️⃣ Model-View-Controller Architecture (MVC)

1. Context

User interfaces are often the most frequently modified part of an interactive application. Users often want to view data from different perspectives, such as bar charts or pie charts. These representations should reflect the current state of the data.

2. Problem

How can user interface functionality be independent of application functionality while still responding to user input or changes in underlying application data?

How can multiple views of the user interface be created, maintained, and coordinated when the underlying application data changes?

3. Solution

The model-view-controller (MVC) pattern divides application functionality into the following three types of components:

  • Model, which contains the application's data.
  • View, which displays part of the underlying data and interacts with the user.
  • Controller, which mediates between the model and view and manages notifications of state changes.

4. Weaknesses

For simple user interfaces, the complexity is not worth it.

Model, view, and controller abstractions may not be suitable for some user interface toolkits.

5. Uses

MVC is a common architectural pattern for developing user interfaces for websites or mobile applications.

6️⃣ Event-driven Architecture

1. Context

It is necessary to provide computing and information resources to handle incoming, independently generated asynchronous events, which can scale as demand increases.

2. Problem

Build a distributed system that can service information about asynchronously arriving events and can scale from small and simple to large and complex.

3. Solution
Deploy independent event processes or processors for event handling. Incoming events enter a queue. A dispatcher pulls events from the queue and assigns them to appropriate event processors based on a scheduling policy.

4. Weaknesses

Performance and error recovery can be issues.

5. Uses

An e-commerce application using this scheme would work as follows:

Order Service creates an Order, which is in a pending state, and then publishes an OrderCreated event.

  • Customer Service receives this event and attempts to deduct credit for this Order. It then publishes a Credit Reserved event or a CreditLimitExceeded event.
  • Order Service receives the event sent by Customer Service and changes the order status to approved or canceled.

7️⃣ Microservices Architecture

1. Context
Deploy server-based enterprise applications that support various browsers and native mobile clients. The application handles client requests by executing business logic, accessing databases, exchanging information with other systems, and returning responses. The application may expose a third-party API.

2. Problem

Monolithic applications can become too large and complex to be effectively supported and deployed to optimize the use of distributed resources, such as in cloud environments.

3. Solution

Build the application as a suite of services. Each service is independently deployable and scalable, with its own API boundary. Different services can be written in different programming languages, manage their own databases, and be developed by different teams.

4. Weaknesses
The system design must tolerate service failures, requiring more system monitoring. Service orchestration and event collaboration overhead is significant.
Of course, we also need more money.

5. Uses
Many use cases can apply the microservices architecture, especially those involving large data pipelines. For example, a microservices system would be ideal for a reporting system on retail store sales for a company. Each step in the data presentation process would be handled by a microservice: data collection, cleaning, normalization, enrichment, aggregation, reporting, etc.