Digital Library
Software Architecture Patterns Understanding Common Architectural Styles and When to Use Them (Mark Richards)(Z-Library)
Software Architecture Patterns Understanding Common Architectural Styles and When to Use Them (Mark Richards)(Z-Library)
代码
No Description
13
Views
0
Downloads
0.00
Total Donations
Text Preview (First 20 pages)
Registered users can read the full content for free
Register as a Gaohf Library member to read the complete e-book online for free and enjoy a better reading experience.
Page
1
(This page has no text content)
Page
2
Mark Richards Software Architecture Patterns Understanding Common Architectural Styles and When to Use Them SECOND EDITION Boston Farnham Sebastopol TokyoBeijing
Page
3
978-1-098-13427-3 [LSI] Software Architecture Patterns by Mark Richards Copyright © 2022 O’Reilly Media, Inc. All rights reserved. Printed in the United States of America. Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472. O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (http://oreilly.com). For more information, contact our corporate/institutional sales department: 800-998-9938 or corporate@oreilly.com. Acquisitions Editor: Melissa Duffield Development Editor: Shira Evans Production Editor: Kristen Brown Copyeditor: Sonia Saruba Interior Designer: David Futato Cover Designer: Randy Comer Illustrator: Rob Romano February 2015: First Edition July 2022: Second Edition Revision History for the Second Edition 2022-07-29: First Release The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. Software Architec‐ ture Patterns, the cover image, and related trade dress are trademarks of O’Reilly Media, Inc. While the publisher and the author have used good faith efforts to ensure that the information and instructions contained in this work are accurate, the publisher and the author disclaim all responsibility for errors or omissions, including without limitation responsibility for damages resulting from the use of or reliance on this work. Use of the information and instructions contained in this work is at your own risk. If any code samples or other technology this work contains or describes is subject to open source licenses or the intellectual property rights of others, it is your responsibility to ensure that your use thereof complies with such licenses and/or rights.
Page
4
Table of Contents 1. Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 2. Architectural Structures and Styles. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Architecture Classification 5 Architecture Partitioning 9 3. Layered Architecture. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 Description 15 Key Concepts 17 Examples 20 Considerations and Analysis 21 4. Microkernel Architecture. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 Topology 25 Examples 27 Considerations and Analysis 29 5. Event-Driven Architecture. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 Topology 33 Example Architecture 35 Event-Driven Versus Message-Driven 37 Considerations and Analysis 38 6. Microservices Architecture. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 Basic Topology 43 What Is a Microservice? 45 Bounded Context 45 iii
Page
5
Unique Features 47 Examples and Use Cases 48 Considerations and Analysis 49 7. Space-Based Architecture. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 Topology and Components 56 Examples 60 Considerations and Analysis 61 A. Style Analysis Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 iv | Table of Contents
Page
6
CHAPTER 1 Introduction It’s all too common for developers to start coding an application without a formal architecture in place. This practice usually results in ill-defined components, creating what is commonly referred to as a big ball of mud. These architectures are generally tightly cou‐ pled, brittle, difficult to change, and lack a clear vision or direction. It’s also very difficult to determine the architectural characteristics of applications lacking a well-defined architectural style. Does the architecture scale? What are the performance characteristics of the application? How easy is it to change the application or add new features? How responsive is the architecture? Architecture styles help define the basic characteristics and behavior of an application. Some architecture styles naturally lend themselves toward highly scalable systems, whereas other architecture styles naturally lend themselves toward applications that allow develop‐ ers to respond quickly to change. Knowing the characteristics, strengths, and weaknesses of each architecture style is necessary to choose the one that meets your specific business needs and goals. A lot has happened in software architecture since 2015 when the first edition of this report was published. Both microservices and event-driven architecture have gained in popularity, and develop‐ ers and architects have found new techniques, tools, and ways of designing and implementing these architecture styles. Also, the widespread use of domain-driven design has led to a better under‐ standing of how architectures are structurally partitioned, and how that partitioning can impact the design and implementation of a 1
Page
7
system. The second edition of the report addresses both of these advances. The second edition also includes other significant enhancements, along with more information about the intersection of architecture and data, and an expanded analysis section at the end of each chap‐ ter. These new sections provide you with better guidelines for when to use (and not to use) each architecture presented in this report. Another change you’ll notice in the second edition is the use of the term architecture style rather than architecture pattern for the architectures described in this report. This distinction helps alleviate some of the confusion surrounding the differences between, say, event-driven architecture—an architecture style—and something like CQRS (Command Query Responsibility Segregation), which is an architecture pattern. An architecture style, such as the ones presented in this report, describe the macro structure of a system. Architecture patterns, on the other hand, describe reusable structural building block patterns that can be used within each of the architecture styles to solve a par‐ ticular problem. Take, for example, the well known CQRS pattern, which describes the structural separation between read and write operations to a database or eventing system (for example, separate services and databases for read operations and write operations). This architecture pattern could be applied to any of the architecture styles described in this report to optimize database queries and updates. Architecture patterns, in turn, differ from design patterns (such as the Builder design pattern) in that an architecture pattern impacts the structural aspect of a system, whereas a design pattern impacts how the source code is designed. For example, you can use the Builder design pattern as a way to implement the CQRS architecture pattern, and then use the CQRS pattern as a building block within a microservices architecture. Figure 1-1 shows this hierarchical rela‐ tionship among the three terms and how they interrelate with each other to build software systems. 2 | Chapter 1: Introduction
Page
8
Figure 1-1. Architecture styles can be composed of architecture pat‐ terns, which in turn can be composed of design patterns Design patterns and architecture patterns are typically combined to form a complete solution. Architecture styles act in the same way— they can also be combined when building software solutions to form a complete solution. Hybrid architecture styles are common in the real world because not every architecture style can solve every busi‐ ness problem. Common architecture style hybrids include event- driven microservices (events between microservices), space-based microservices (processing units implemented as microservices), and even an event-driven microkernel architecture (events between the core system and remote plug-in components). Although forming hybrids is a common practice, it is vital to understand individ‐ ual architecture styles and their corresponding strengths and weak‐ nesses before combining them. The goal of this updated second edition report remains the same as the first edition: to help senior developers and architects understand some of the more common architecture styles, how they work, when to use them, and when not to use them. This will help to not only expand your knowledge of architecture, but will also help you make the right architecture choice for your systems. Introduction | 3
Page
9
(This page has no text content)
Page
10
CHAPTER 2 Architectural Structures and Styles Architecture styles allow you to use existing and well-known struc‐ tures that support certain architectural characteristics (also known as nonfunctional quality attributes, system quality attributes, or “-ilities”). They not only provide you with a head start on defining an architecture for a given system, but they also facilitate communi‐ cation among developers, architects, quality assurance testers, oper‐ ations experts, and even in some cases, business stakeholders. Architecture Classification Architecture styles are classified as belonging to one of two main architectural structures: monolithic (single deployment unit) and distributed (multiple deployment units, usually consisting of serv‐ ices). This classification is important to understand because as a group, distributed architectures support much different architecture characteristics than monolithic ones. Knowing which classification of architecture to use is the first step in selecting the right architec‐ ture for your business problem. Monolithic Architectures Monolithic architecture styles (as illustrated in Figure 2-1) are gen‐ erally much simpler than distributed ones, and as such are easier to design and implement. These single deployment unit applications are fairly inexpensive from an overall cost standpoint. Furthermore, most applications architected using a monolithic architecture style 5
Page
11
can be developed and deployed much more quickly than distributed ones. Figure 2-1. Monolithic architectures are single deployment units While cost and simplicity are the main strong points of a monolithic architecture, operational characteristics such as scalability, fault tol‐ erance, and elasticity are its weak points. A fatal error (such as an out of memory condition) in a monolithic architecture causes all of the functionality to fail. Furthermore, mean time to recovery (MTTR) and mean time to start (MTTS) are usually measured in minutes, meaning that once a failure does occur, it takes a long time for the application to start back up. These long startup times also impact scalability and elasticity. While scalability can sometimes be achieved through load balancing multiple instances of the applica‐ tion, the entire application functionality must scale, even if only a small portion of the overall application needs to scale. This is not only inefficient, but unnecessarily costly as well. Examples of monolithic architecture styles include the layered architecture (described in Chapter 3), the modular monolith, the pipeline architecture, and the microkernel architecture (described in Chapter 4). 6 | Chapter 2: Architectural Structures and Styles
Page
12
Distributed Architectures As the name suggests, distributed architectures consist of multiple deployment units that work together to perform some sort of cohe‐ sive business function. In today’s world, most distributed architec‐ tures consist of services, although each distributed architecture style has its own unique formal name for a service. Figure 2-2 illustrates a typical distributed architecture. Figure 2-2. Distributed architectures consist of multiple deployment units The superpowers of distributed architectures usually fall within operational characteristics—things like scalability, elasticity, fault tolerance, and in some cases, performance. Scalability in these architecture styles is typically at the individual service level, as is elasticity. Hence, MTTS and MTTR are much smaller than with a monolithic application, measured usually in seconds (and in some cases milliseconds) rather than minutes. Distributed architectures are well suited for supporting high levels of fault tolerance. If one service fails, in many cases other services can continue to service requests as if no fault happened. Services that do fail can recover very quickly—so quickly that at times an end user sometimes doesn’t even know the service had a fatal error. Architecture Classification | 7
Page
13
Agility (the ability to respond quickly to change) is often another superpower of distributed architectures. Because application func‐ tionality is divided into separately deployed units of software, it is easier to locate and apply a change, the testing scope is reduced to only the service that is impacted, and deployment risk is sig‐ nificantly reduced because only the service impacted is typically deployed. Unfortunately, with all those good features come some bad features as well. Distributed architectures are plagued with what are known as the fallacies of distributed computing, a set of eight things we believe to be true about networks and distributed computing, but are in fact false. Things like “the network is reliable,” “bandwidth is infinite,” and “latency is zero” all make distributed architectures not only hard to keep deterministic, but also hard to make completely reliable. Networks do fail, bandwidth is not infinite, and latency is not zero. These things are as real today as they were back in the late ’90s when they were coined. In addition to the eight fallacies of distributed computing, other difficulties arise with distributed architectures. Distributed transac‐ tions, eventual consistency, workflow management, error handling, data synchronization, contract management, and a host of other complexities are all part of the world of distributed architecture. To top it off, all this complexity usually means much more cost from an overall initial implementation and ongoing maintenance cost than monolithic architectures. Suddenly, all of those great superpowers don’t sound so great anymore when you consider all the trade-offs of distributed architectures. Examples of distributed architectures include event-driven archi‐ tecture (described in Chapter 5), the ever-popular microservices architecture (described in Chapter 6), service-based architec‐ ture, service-oriented architecture, and space-based architecture (described in Chapter 7). Which One Should I Choose? When choosing between a monolithic versus a distributed architec‐ ture, one question to first ask yourself is if the system you are creating has different sets of architecture characteristics that must be supported. In other words, does the entire system need to scale and support high availability, or only parts of the system? Systems 8 | Chapter 2: Architectural Structures and Styles
Page
14
that contain multiple sets of different architecture characteristics generally call for a distributed architecture. A good example of this is customer-facing functionality requiring support for scalability, responsiveness, availability, and agility, and an administrative or backend processing functionality that doesn’t need any of those characteristics. Simple systems or websites usually warrant the simpler and more cost-effective monolithic architecture style, whereas more complex systems that perform multiple business functions usually warrant more complex distributed architectures. Similarly, the “need for speed,” the need for high volumes of scalability, and the need for high fault tolerance are all characteristics that lend themselves toward distributed architectures. Architecture Partitioning Besides being classified as either monolithic or distributed, architec‐ tures can also be classified by the way the overall structure of the system is partitioned. Architectures, whether they are monolithic or distributed, can be either technically partitioned or domain par‐ titioned. The following sections describe the differences between these partitioning structures and why it’s important to understand them. Technical Partitioning Technically partitioned architectures have the components of the system organized by technical usage. The classic example of a techni‐ cally partitioned architecture is the layered (n-tiered) architecture style (see Chapter 3). In this architecture style, components are organized by technical layers; for example, presentation components that have to do with the user interface, business layer components that have to do with business rules and core processing, persistence layer components that interact with the database, and the database layer containing the data for the system. Notice in Figure 2-3 that the components of any given domain are spread across all of these technical layers. For example, the customer domain functionality resides in the presentation layer as customer screens, the business layer as customer logic, the presentation layer as customer queries, and the database layer as customer tables. Manifested as namespaces, these components would be organized Architecture Partitioning | 9
Page
15
as follows: app.presentation.customer, app.business.customer, app.persistence.customer, and so on. Notice how the second node in the namespace specifies the technical layering, and that the customer node is spread across those layers. Figure 2-3. In a technically partitioned architecture, components are grouped by their technical usage Technically partitioned architectures are useful if a majority of your changes are isolated to a specific technical area in the application. For example, if you are constantly changing the look and feel of your user interface without changing the corresponding business rules, change is isolated to only one part of the architecture (in this case, the presentation layer). Similarly, if your business rules are constantly changing but there is no impact to the data layer or presentation layer, changes are isolated to the business layer of the architecture with no impact to other parts of the system. However, imagine implementing a new requirement to add an expiration data to items for customer wish lists in a technically partitioned architecture. This type of change is considered a domain-based change (not a technical usage one), and impacts all of the layers of the architecture. To implement this change, you would need to add a new column to the wish list table in the database layer, change the corresponding SQL in the persistence layer, add the corresponding business rules to components in the business layer, change the contracts between the business and presentation layer, 10 | Chapter 2: Architectural Structures and Styles
Page
16
and finally change the screens in the presentation layer. Depending on the size of the system and the team structure, this simple change might involve the coordination of three to four different teams. Examples of technically partitioned architectures include the lay‐ ered architecture (Chapter 3), microkernel architecture (Chapter 4), pipeline architecture, event-driven architecture (Chapter 5), and space-based architecture (Chapter 7). Microkernel architecture is particularly interesting in that it’s the only architecture style that can be either technically partitioned or domain partitioned depending on how the plug-in components are used. For example, when the plug-in components are used as adapters or special configuration settings, it would be considered technically partitioned. Domain Partitioning Unlike technically partitioned architectures, components in domain partitioned architectures are organized by domain areas, not tech‐ nical usage. This means that all of the functionality (presentation, business logic, and persistence logic) is grouped together for each domain and subdomain area in separate areas of the application. For domain partitioned architectures, components might be manifested through a namespace structure such as app.customer, app.ship ping, app.payment, and so on. Notice that the second node rep‐ resents the domain rather than a technical layer. As a matter of fact, domains can be further organized into technical layering if so desired, which might take the form app.customer.presentation, app.customer.business, and so on. Notice that even though the customer domain logic may be organized by technical usage, the primary structure (represented as the second node of the name‐ space) is still partitioned by domain. Figure 2-4 shows a typical example of a domain partitioned architecture. Domain partitioned architectures have grown in popularity over the years in part due to the increased use and acceptance of domain- driven design, a software modeling and analysis technique coined by Eric Evans. Domain-driven design places an emphasis on the design of a domain rather than on complex workflows and technical components. This approach allows teams to collaborate closely with domain experts and focus on one key part of the system, thus devel‐ oping software that closely resembles that domain functionality. Architecture Partitioning | 11
Page
17
Figure 2-4. In a domain partitioned architecture, components are grouped by domain area The clear advantage of domain partitioning within an architecture is that changes to a particular domain or subdomain are self-contained within a specific area of the system, allowing teams to pinpoint exactly the area of the system that requires the change. Coming back to our implementation of expiration data for a cus‐ tomer’s wish list items, with domain partitioning the changes in code are isolated to only one small part of the system, making this type of change much more effective than with technical partitioning. Here, for example, changes would be isolated to the namespace starting with app.customer.wishlist, meaning that presentation logic, business logic, and persistence logic are all within the same area of the system. Maintenance is easier, testing is easier, and deployment is much less risky when these types of changes are done. Examples of domain partitioned architectures include the microker‐ nel architecture (Chapter 4), microservices architecture (Chapter 6), modular monolith architecture, and service-based architecture. As indicated earlier, microkernel architecture can be either technically partitioned or domain partitioned. If the plug-in components are used to extend the application by adding functionality, then it would be considered a domain partitioned architecture. 12 | Chapter 2: Architectural Structures and Styles
Page
18
Which One Should I Choose? The choice between a technically partitioned architecture and a domain partitioned architecture is an important one. The overall structure of the architecture must be aligned not only with the team structure, but also with the nature of the types of changes expected in the system in order to be successful and effective. Technically partitioned architectures (whether monolithic or dis‐ tributed) are well suited when your overall team structure is organ‐ ized by those same technical usage areas. For example, if your development teams are organized as teams of user interface devel‐ opers, backend developers, and database developers, technically partitioned architectures would be a good fit because the team struc‐ ture matches the technical layers of the architecture. Technically partitioned architectures are also a natural fit when most of your expected changes are aligned with technical layers (for example, multiple user interfaces, changes to the look and feel of the system, swapping out one database for another, and so on). If you are embarking on a new system and using a domain-driven design approach, then you should in turn consider a domain par‐ titioned architecture. Also, domain partitioned architectures are a great fit if your teams are organized into cross-functional teams with specialization—in other words, single teams that are aligned with specific domain functionality and contain user interface developers, backend developers, and database developers all on the same physi‐ cal team. Domain partitioned architectures are also a good choice when you expect most of your changes to be domain scoped rather than tech‐ nical usage scoped. This allows for much better agility (the ability to respond quickly to change) than with technically partitioned architectures. However, be careful when choosing a domain parti‐ tioned architecture if you have lots of changes to technical usage layers. For example, swapping out one database type for another or changing the entire user interface framework would be a difficult and time-consuming task in a domain partitioned architecture. Architecture Partitioning | 13
Page
19
(This page has no text content)
Page
20
CHAPTER 3 Layered Architecture The most common architecture style is the layered architecture, otherwise known as the n-tier architecture. This style is the de facto standard for most applications because it aligns with traditional IT team structures where teams are organized by technical domains (such as presentation teams, backend development teams, database teams, and so on). Because it is so widely known by most archi‐ tects, designers, and developers, the layered architecture is a natural choice for most business application development efforts. However, like all architecture styles, it has its strengths and weaknesses and is not always suitable for some systems. Description Components within the layered architecture style are organized into horizontal layers, each performing a specific role within the application (such as presentation logic, business logic, persistence logic, and so on). Although the number of layers may vary, most layered architectures consist of four standard layers: presentation, business, persistence, and database (see Figure 3-1). In some cases, the business layer and persistence layer are combined into a single business layer, particularly when the persistence logic (such as SQL) is embedded within the business layer components. Thus, smaller applications may have only three layers, whereas larger and more complex business applications may contain five or more layers. 15
The above is a preview of the first 20 pages. Register to read the complete e-book.
Support Author
0.00
Total Amount (¥)
0
Donation Count
Please enter an amount
Minimum ¥1
You will be redirected to Alipay to complete payment, then return here.
Order created — please complete Alipay payment
{{#payUrl}} Pay with Alipay {{/payUrl}} {{^payUrl}}{{message}}
{{/payUrl}}
Donation failed:{{message}}
Log in to link the donation to your account (anonymous payment also works)
Recommended for You
{{#thumbnailUrl}}
{{/thumbnailUrl}}
{{^thumbnailUrl}}
{{/thumbnailUrl}}
Loading recommended books...
Failed to load, please try again later