Software Architecture Patterns Overview
https://www.youtube.com/watch?app=desktop&v=f6zXyq4VPP8

Software Architecture Patterns Overview

Introduction

Imagine millions of users relying on a single application. How do you ensure it runs smoothly and scales effectively? Software architecture patterns provide some of the answers! The article's targets are software developers, software engineers, architects, and anyone interested in building or understanding complex software systems

Here, you will see a high-level overview of software architecture and system design patterns, exploring their strengths, weaknesses, best practices, and real-world applications. It also explains the difference between system design, software architecture, and software design.

This article focuses on software architecture patterns, which include system design patterns. You will find lots of documentation around the web mixing or separating these categories. I choose to aggregate since it's an overview and there's a very subtle and not well-documented line between them. Let's see, first, what Martin C Robert, in the first chapter of the Clean Architecture book, says about the difference:

... For starters, I’ll assert that there is no difference between them. None at all. The word “architecture” is often used in the context of something at a high level that is divorced from the lower-level details, whereas “design” more often seems to imply structures and decisions at a lower level. But this usage is nonsensical when you look at what a real architect does.

In a very resumed explanation, we can consider that design = detailed, so both system design and software design have a detailed approach:

  • System design: It focuses on the details of the whole system, including hardware, software, network, overall components, and their interactions. Scalability, performance, and fault tolerance are some of the key considerations when building a robust system
  • Software architecture: It defines the high-level structure of the software, including communication between components and key technical decisions that impact those considerations mentioned above.
  • Software design: has a detailed description of the software itself, that can be a part(component or module) of the entire system. However, it's not limited to just a part of the system. It can be a single well-defined component or an entire system if it's relatively simple

Suppose you want to learn more about System Design. In that case, you can read my article explaining system design from a requirements perspective or my other article demystifying common jargon of system design.

I will skip the software design patterns overview since it's very well-documented and vast. Now, let's depict software architecture patterns. By understanding these patterns, you can equip yourself to make informed decisions when designing and building complex systems.

Monolithic Architecture

https://www.atlassian.com/microservices/microservices-architecture/microservices-vs-monolith#:~:text=A%20monolithic%20architecture%20is%20a%20singular%2C%20large%20computing%20network%20with,of%20the%20service%2Dside%20interface

In software development, a monolithic architecture represents a traditional approach where the entire application is built as a single, self-contained unit. Imagine it like a well-oiled machine, where all the components work together seamlessly.

It may be the simpler architectural pattern but I can grant you that it can resolve most of the common system necessities without technical debts

Here's a breakdown of its pros and cons to help you decide if it's the right fit for your project:

Pros

  • Simplicity: Monolithic applications are generally easier to develop and maintain, especially for smaller projects. With everything in one codebase, developers clearly understand how different parts interact.
  • Performance: Monolithic architecture can deliver excellent performance for less complex applications due to tight integration between components.

Cons

  • Scalability: As your application grows in complexity and user base, scaling a monolithic architecture becomes challenging. Adding new features or handling increased traffic can strain the entire system.

  • Maintainability: Changes in one part of the monolithic application can ripple through the entire system, impacting other functionalities. This can make maintenance cumbersome and time-consuming.
  • Deployment: Deploying updates in a monolithic system often requires bringing down the entire application. This can lead to downtime and disrupt user experience.

Best Practices

  • Ideal for small, well-defined applications: Monolithic architecture shines for projects with a limited scope, a small user base, and a small team of engineers.
  • Transition to new patterns when complexity arises: As your application evolves and grows in complexity, consider transitioning to a Three-Tier Architecture or Microservices Architecture. This approach breaks down the application into smaller components.

Real-World Example

A simple blog with few functionalities, like Stackoverflow, but smaller. It's good to point out that most of the StackOverflow codebase is still a monolith


Three Tier Architecture

https://www.geeksforgeeks.org/three-tier-client-server-architecture-in-distributed-system/

Three-tier architecture is a popular software design pattern that separates a system into three horizontal layers, each with a specific responsibility. Although it might look the same as the MVC pattern, it's different. In the MVC pattern, the View and the Controller are in the Presentation tier, and the Model is in the Business tier. Here are the tiers in a three-tier architecture:

  • Presentation Tier: This layer handles user interaction, including web interfaces, mobile apps, or desktop applications. It presents data and functionality to the user and captures user input.
  • Application Tier (Business Tier or Logic Tier): This layer sits behind the scenes and is the brain of the operation. It processes business logic, implements core functionalities, and interacts with the database tier.
  • Database Tier: This layer is responsible for storing and managing persistent data. It can be a relational database, NoSQL database, or any other data storage solution.


Pros

  • Scalability: Individual tiers can be scaled independently to meet specific needs. For example, you can upgrade the database server to handle more data while keeping the presentation tier unchanged.
  • Maintainability: The clear separation of concerns simplifies maintenance. Developers can focus on modifying a specific layer without worrying about unintended consequences in other parts.
  • Reusability: Components within a tier can potentially be reused across different applications. This promotes code efficiency and reduces development time.

Cons

  • Complexity: As the application grows, managing interactions and dependencies between the tiers can become complex.
  • Performance Bottlenecks: Performance issues in one tier can impact the entire application. For instance, a slow database can lead to sluggishness throughout the system.

Real-World Example

A three-tier architecture is well-suited for most small-medium size e-commerce applications. The separation bellow allows for independent scaling of the user interface during peak shopping seasons while ensuring smooth order processing through the application tier:

  • The presentation tier: would be the user interface (website or mobile app) with static pages for browsing products and adding them to a cart.

  • The application tier: would handle functionalities like shopping cart management, getting products available, checkout processes, and order fulfillment.
  • The database tier: would store product information, user data, and order details.


Microservices Architecture

A microservices architecture decomposes an application into small, independent services, each with its own functionality, database, and deployment lifecycle.

Pros

  • Agility: Faster development and deployment cycles due to independent services.
  • Scalability: Individual services can be scaled independently based on load.
  • Fault Tolerance: Failure of one service doesn't bring down the entire system.

Cons

  • Complexity: Requires careful planning and coordination to avoid distributed system challenges like distributed tracing and debugging.
  • Overhead: Communication between services can introduce overhead compared to monolithic architectures.

Best Practices

  • 12 Factors-App is a must if you are building a Web App or SaaS. It tells you how to structure your microservices: CI/CD, monitoring, dependencies, code management, communication patterns, etc.

  • Define clear boundaries between services using the Single Responsibility Principle (SRP).
  • Design APIs for communication between services.
  • Implement automated deployment and testing for each service.

Real-World Example

Netflix, Amazon, and Spotify all leverage microservices architectures in their system, along with other architectural patterns for big data.


Event-Driven Architecture (EDA)

An event-driven architecture uses events to trigger actions and interactions between services. Services publish events to a message broker, and other services interested in those events subscribe to them. This promotes loose coupling and asynchronous communication.

Pros

  • Scalability: Easier to handle large volumes of data (big data) in real time.
  • Resilience: Failure of one component doesn't necessarily impact others as communication is asynchronous.

Cons

  • Complexity: Debugging and error handling can be more challenging due to asynchronous communication.

Best Practices

  • Define a clear event schema for communication.
  • Implement a reliable message broker for event delivery.
  • Use asynchronous programming patterns within services.

Real-World Example

Many messaging applications and real-time analytics platforms use EDA.


Batch Processing

It's probably the only pattern that Isn't an architectural one in this article, but a data processing one, although is here due to it's importance in overall software systems. Batch processing handles large datasets in bulk, often overnight, for historical analysis. This approach is cost-effective but not suitable for real-time needs.

Pros

  • Cost-effective: Leverages idle compute resources during off-peak hours.
  • Scalability: Can handle large datasets efficiently.

Cons

  • Latency: Data analysis results are not available in real-time.
  • Not suitable for real-time applications


Saga Pattern

https://medium.com/aws-lambda-serverless-developer-guide-with-hands/saga-pattern-for-orchestrate-distributed-transactions-using-aws-step-functions-2513db0de84e


The Saga pattern is a transactional messaging pattern for managing long-running business processes that flow through multiple microservices. It coordinates a sequence of local transactions across services to ensure data consistency in case of failures. Each service is responsible for rolling back what it has done in case of failure in any service related to it in the flow of a given operation.

Although I'm categorizing it as a Database pattern, it's not limited to database transactions. As you can see in the image, the SAGA Pattern can end in a refund to a client if some error appears during the buying process.

Pros

  • Distributed Transactions: Manages complex workflows across multiple microservices with eventual consistency.
  • Fault Tolerance: Compensating transactions can undo changes in case of failures during the saga, ensuring data integrity.
  • Scalability: Individual microservices can be scaled independently without impacting the overall saga flow.

Cons

  • Complexity: Implementing and debugging sagas can be challenging due to their distributed nature.
  • Eventual Consistency: Data consistency across services might not be immediate, similar to CQRS.

Best Practices

  • Define clear boundaries and steps involved in the saga workflow.
  • Utilize event sourcing to track the state of the saga and enable compensating transactions.
  • Implement robust error handling and compensation mechanisms for potential failures.

Real-World Example

Let's explain the image above:

  • A user places an order through the AWS API Gateway.
  • The API Gateway receives the order and sends it to the Order microservice.
  • The Order microservice interacts with the Inventory microservice to check product availability.
  • If inventory is available, the Order microservice communicates with a third-party Payment microservice to process the payment.
  • Upon successful payment, the Order microservice updates the Order table and the Inventory table.
  • If any of the microservices fail during the process (like payment failure), a compensating transaction is triggered to revert changes made to other microservices (like reversing the inventory reservation).
  • Finally, the successful order fulfillment is logged in Amazon CloudWatch.


CQRS

Command Query Responsibility Segregation

CQRS is a software architecture pattern that separates read (queries) and write (commands) operations into different models and databases. This improves scalability, performance, and maintainability for applications with high read traffic.

Pros

  • Scalability: Read and write models can be scaled independently based on their specific needs. You can scale the read model to handle high query volume without impacting write performance and vice versa.
  • Performance: Optimized models for reads and writes improve query performance and data consistency for writes.
  • Maintainability: Separation of concerns simplifies development and maintenance. Developers working on read models don't need to worry about write logic, and vice versa.

Cons

  • Complexity: Implementing and managing separate models and databases can be more complex than traditional architectures.
  • Eventual Consistency: Depending on the implementation, data consistency between read and write models might not be immediate (eventual consistency). That is what the CAP Theorem is about and I explained it in my previous article demystifying common jargon of system design.

Best Practices

  • Clearly define the boundaries between commands and queries.
  • Use different databases for read and write models based on their access patterns. (e.g., relational database for writes, NoSQL database for reads)
  • Implement mechanisms to ensure eventual consistency between models. (e.g., materialized views, event sourcing)

Real-World Example

E-commerce applications with a high volume of product searches (reads) and a lower volume of order placements (writes) can benefit from CQRS. The product catalog can be a read model optimized for fast searches, while the order processing system can be a separate write model.

要查看或添加评论,请登录

社区洞察

其他会员也浏览了