Software Architecture and Design¶
Table Of Contents
- Software Architecture and Design
- Software Architecture and Design
- Chapter 1: What is Software Architecture?
- Chapter 2: Key Principles of Software Architecture
- Chapter 3: Architectural Patterns and Styles
- Chapter 4: A Technique for Architecture and Design
- Inputs, Outputs, and Design Steps
- Identify Architecture Objectives
- Scope and Time
- Key Scenarios
- Architecturally Significant Use Cases
- Application Overview
- Relevant Technologies
- Whiteboard Your Architecture
- Key Issues
- Quality Attributes
- Crosscutting Concerns
- Designing for Issue Mitigation
- Candidate Solutions
- Baseline and Candidate Architectures
- Architectural Spikes
- What to Do Next
- Reviewing Your Architecture
- Representing and Communicating Your Architecture Design
Software Architecture and Design¶
This section of the guide contains a series of topics that will help you to understand the fundamentals of architecture and design. It starts by describing what is software architecture is, why is it important. It discusses the general issues you must consider, such as requirements and constraints and the intersection between the user, the business, and the system on which the application will run. This is followed by a description of the key design principles, and the architectural patterns and styles in common use today. Finally, this section provides an insight into the approach you should follow when designing your architecture. For more information, see the following chapters:
Chapter 1 "What is Software Architecture?" Chapter 2 "Key Principles of Software Architecture" Chapter 3 "Architectural Patterns and Styles" Chapter 4 "A Technique for Architecture and Design"
Chapter 1: What is Software Architecture?¶
- What is Software Architecture?
- The Goals of Architecture
- The Principles of Architecture Design
What is Software Architecture?¶
Software application architecture is the process of defining a structured solution that meets all of the technical and operational requirements, while optimizing common quality attributes such as performance, security, and manageability. It involves a series of decisions based on a wide range of factors, and each of these decisions can have considerable impact on the quality, performance, maintainability, and overall success of the application.
Philippe Kruchten, Grady Booch, Kurt Bittner, and Rich Reitman derived and refined a definition of architecture based on work by Mary Shaw and David Garlan (Shaw and Garlan 1996). Their definition is:
“Software architecture encompasses the set of significant decisions about the organization of a software system including the selection of the structural elements and their interfaces by which the system is composed; behavior as specified in collaboration among those elements; composition of these structural and behavioral elements into larger subsystems; and an architectural style that guides this organization. Software architecture also involves functionality, usability, resilience, performance, reuse, comprehensibility, economic and technology constraints, tradeoffs and aesthetic concerns.”
In Patterns of Enterprise Application Architecture, Martin Fowler outlines some common recurring themes when explaining architecture. He identifies these themes as:
“The highest‐level breakdown of a system into its parts; the decisions that are hard to change; there are multiple architectures in a system; what is architecturally significant can change over a system's lifetime; and, in the end, architecture boils down to whatever the important stuff is.”
[http://www.pearsonhighered.com/educator/academic/product/0,3110,0321127420,00.html]
In Software Architecture in Practice (2nd edition), Bass, Clements, and Kazman define architecture as follows:
“The software architecture of a program or computing system is the structure or structures of the system, which comprise software elements, the externally visible properties of those elements, and the relationships among them. Architecture is concerned with the public side of interfaces; private details of elements—details having to do solely with internal implementation—are not architectural.”
[http://www.pearsonhighered.com/educator/academic/product/0,4096,0321154959,00.html]
Why is Architecture Important?¶
Like any other complex structure, software must be built on a solid foundation. Failing to consider key scenarios, failing to design for common problems, or failing to appreciate the long term consequences of key decisions can put your application at risk. Modern tools and platforms help to simplify the task of building applications, but they do not replace the need to design your application carefully, based on your specific scenarios and requirements. The risks exposed by poor architecture include software that is unstable, is unable to support existing or future business requirements, or is difficult to deploy or manage in a production environment.
Systems should be designed with consideration for the user, the system (the IT infrastructure), and the business goals. For each of these areas, you should outline key scenarios and identify important quality attributes (for example, reliability or scalability) and key areas of satisfaction and dissatisfaction. Where possible, develop and consider metrics that measure success in each of these areas.
Figure 1
User, business, and system goals
Tradeoffs are likely, and a balance must often be found between competing requirements across these three areas. For example, the overall user experience of the solution is very often a function of the business and the IT infrastructure, and changes in one or the other can significantly affect the resulting user experience. Similarly, changes in the user experience requirements can have significant impact on the business and IT infrastructure requirements. Performance might be a major user and business goal, but the system administrator may not be able to invest in the hardware required to meet that goal 100 percent of the time. A balance point might be to meet the goal only 80 percent of the time.
Architecture focuses on how the major elements and components within an application are used by, or interact with, other major elements and components within the application. The selection of data structures and algorithms or the implementation details of individual components are design concerns. Architecture and design concerns very often overlap. Rather than use hard and fast rules to distinguish between architecture and design, it makes sense to combine these two areas. In some cases, decisions are clearly more architectural in nature. In other cases, the decisions are more about design, and how they help you to realize that architecture.
By following the processes described in this guide, and using the information it contains, you will be able to construct architectural solutions that address all of the relevant concerns, can be deployed on your chosen infrastructure, and provide results that meet the original aims and objectives.
Consider the following high level concerns when thinking about software architecture:
- How will the users be using the application?
- How will the application be deployed into production and managed?
- What are the quality attribute requirements for the application, such as security, performance, concurrency, internationalization, and configuration?
- How can the application be designed to be flexible and maintainable over time
- What are the architectural trends that might impact your application now or after it has been deployed?
The Goals of Architecture¶
Application architecture seeks to build a bridge between business requirements and technical requirements by understanding use cases, and then finding ways to implement those use cases in the software. The goal of architecture is to identify the requirements that affect the structure of the application. Good architecture reduces the business risks associated with building a technical solution. A good design is sufficiently flexible to be able to handle the natural drift that will occur over time in hardware and software technology, as well as in user scenarios and requirements. An architect must consider the overall effect of design decisions, the inherent tradeoffs between quality attributes (such as performance and security), and the tradeoffs required to address user, system, and business requirements.
Keep in mind that the architecture should:
Expose the structure of the system but hide the implementation details.Realize all of the use cases and scenarios.
Try to address the requirements of various stakeholders.
Handle both functional and quality requirements.
The Architectural Landscape¶
It is important to understand the key forces that are shaping architectural decisions today, and which will change how architectural decisions are made in the future. These key forces are driven by user demand, as well as by business demand for faster results, better support for varying work styles and workflows, and improved adaptability of software design.
Consider the following key trends:
- User empowerment. A design that supports user empowerment is flexible, configurable, and focused on the user experience. Design your application with appropriate levels of user personalization and options in mind. Allow the user to define how they interact with your application instead of dictating to them, but do not overload them with unnecessary options and settings that can lead to confusion. Understand the key scenarios and make them as simple as possible; make it easy to find information and use the application.
- Market maturity. Take advantage of market maturity by taking advantage of existing platform and technology options. Build on higher level application frameworks where it makes sense, so that you can focus on what is uniquely valuable in your application rather than recreating something that already exists and can be reused. Use patterns that provide rich sources of proven solutions for common problems.
- Flexible design. Increasingly, flexible designs take advantage of loose coupling to allow reuse and to improve maintainability. Pluggable designs allow you to provide post- deployment extensibility. You can also take advantage of service orientation techniques such as SOA to provide interoperability with other systems.
- Future trends. When building your architecture, understand the future trends that might affect your design after deployment. For example, consider trends in rich UI and media, composition models such as mashups, increasing network bandwidth and availability, increasing use of mobile devices, continued improvement in hardware performance, interest in community and personal publishing models, the rise of cloud-based computing, and remote operation.
The Principles of Architecture Design¶
Current thinking on architecture assumes that your design will evolve over time and that you cannot know everything you need to know up front in order to fully architect your system. Your design will generally need to evolve during the implementation stages of the application as you learn more, and as you test the design against real world requirements. Create your architecture with this evolution in mind so that it will be able to adapt to requirements that are not fully known at the start of the design process.
Consider the following questions as you create an architectural design
- What are the foundational parts of the architecture that represent the greatest risk if you get them wrong?
- What are the parts of the architecture that are most likely to change, or whose design you can delay until later with little impact?
- What are your key assumptions, and how will you test them?
- What conditions may require you to refactor the design?
Do not attempt to over engineer the architecture, and do not make assumptions that you cannot verify. Instead, keep your options open for future change. There will be aspects of your design that you must fix early in the process, which may represent significant cost if redesign is required. Identify these areas quickly and invest the time necessary to get them right.
Key Architecture Principles¶
Consider the following key principles when designing your architecture:
- Build to change instead of building to last. Consider how the application may need to change over time to address new requirements and challenges, and build in the flexibility to support this.
- Model to analyze and reduce risk. Use design tools, modeling systems such as Unified Modeling Language (UML), and visualizations where appropriate to help you capture requirements and architectural and design decisions, and to analyze their impact. However, do not formalize the model to the extent that it suppresses the capability to iterate and adapt the design easily.
- Use models and visualizations as a communication and collaboration tool. Efficient communication of the design, the decisions you make, and ongoing changes to the design, is critical to good architecture. Use models, views, and other visualizations of the architecture to communicate and share your design efficiently with all the stakeholders, and to enable rapid communication of changes to the design.
- Identify key engineering decisions. Use the information in this guide to understand the key engineering decisions and the areas where mistakes are most often made. Invest in getting these key decisions right the first time so that the design is more flexible and less likely to be broken by changes.
Consider using an incremental and iterative approach to refining your architecture. Start with a baseline architecture to get the big picture right, and then evolve candidate architectures as you iteratively test and improve your architecture. Do not try to get it all right the first time—design just as much as you can in order to start testing the design against requirements and assumptions. Iteratively add details to the design over multiple passes to make sure that you get the big decisions right first, and then focus on the details. A common pitfall is to dive into the details too quickly and get the big decisions wrong by making incorrect assumptions, or by failing to evaluate your architecture effectively. When testing your architecture, consider the following questions:
- What assumptions have I made in this architecture?
- What explicit or implied requirements is this architecture meeting?
- What are the key risks with this architectural approach?
- What countermeasures are in place to mitigate key risks?
- In what ways is this architecture an improvement over the baseline or the last candidate architecture?
For more information about the key principles of software architecture design, see Chapter 2 "Key Principles of Software Architecture."
For information about the incremental and iterative approach to architecture, baseline and candidate architectures, and representing and communicating the design, see Chapter 4 "A Technique for Architecture and Design."
Chapter 2: Key Principles of Software Architecture¶
Contents
- Overview
- Key Design Principles
- Key Design Considerations
Overview¶
In this chapter, you will learn about the key design principles and guidelines for software architecture. Software architecture is often described as the organization or structure of a system, where the system represents a collection of components that accomplish a specific function or set of functions. In other words, architecture is focused on organizing components to support specific functionality. This organization of functionality is often referred to as grouping components into “areas of concern.” Figure 1 illustrates common application architecture with components grouped by different areas of concern.
Figure 1
Common application architecture
In addition to the grouping of components, other areas of concern focus on interaction between the components and how different components work together. The guidelines in this chapter examine different areas of concern that you should consider when designing the architecture of your application.
Key Design Principles¶
When getting started with your design, keep in mind the key principles that will help you to create an architecture that adheres to proven principles, minimizes costs and maintenance requirements, and promotes usability and extendibility. The key principles are:
- Separation of concerns. Divide your application into distinct features with as little overlap in functionality as possible. The important factor is minimization of interaction points to achieve high cohesion and low coupling. However, separating functionality at the wrong boundaries can result in high coupling and complexity between features even though the contained functionality within a feature does not significantly overlap.
- Single Responsibility principle. Each component or module should be responsible for only a specific feature or functionality, or aggregation of cohesive functionality.
- Principle of Least Knowledge (also known as the Law of Demeter or LoD). A component or object should not know about internal details of other components or objects.
- Don’t repeat yourself ﴾DRY﴿. You should only need to specify intent in one place. For example, in terms of application design, specific functionality should be implemented in only one component; the functionality should not be duplicated in any other component.
- Minimize upfront design. Only design what is necessary. In some cases, you may require upfront comprehensive design and testing if the cost of development or a failure in the design is very high. In other cases, especially for agile development, you can avoid big design upfront (BDUF). If your application requirements are unclear, or if there is a possibility of the design evolving over time, avoid making a large design effort prematurely. This principle is sometimes known as YAGNI ﴾"You ain’t gonna need it"﴿.
When designing an application or system, the goal of a software architect is to minimize the complexity by separating the design into different areas of concern. For example, the user interface (UI), business processing, and data access all represent different areas of concern. Within each area, the components you design should focus on that specific area and should not mix code from other areas of concern. For example, UI processing components should not include code that directly accesses a data source, but instead should use either business components or data access components to retrieve data.
However, you must also make a cost/value determination on the investment you make for an application. In some cases, you may need to simplify the structure to allow, for example, UI data binding to a result set. In general, try to consider the functional boundaries from a business viewpoint as well. The following high level guidelines will help you to consider the wide range of factors that can affect the ease of designing, implementing, deploying, testing, and maintaining your application.
Design Practices
- Keep design patterns consistent within each layer. Within a logical layer, where possible, the design of components should be consistent for a particular operation. For example, if you choose to use the Table Data Gateway pattern to create an object that acts as a gateway to tables or views in a database, you should not include another pattern such as Repository, which uses a different paradigm for accessing data and initializing business entities. However, you may need to use different patterns for tasks in a layer that have a large variation in requirements, such as an application that contains business transaction and reporting functionality.
- Do not duplicate functionality within an application. There should be only one component providing a specific functionality—this functionality should not be duplicated in any other component. This makes your components cohesive and makes it easier to optimize the components if a specific feature or functionality changes. Duplication of functionality within an application can make it difficult to implement changes, decrease clarity, and introduce potential inconsistencies.
- Prefer composition to inheritance. Wherever possible, use composition over inheritance when reusing functionality because inheritance increases the dependency between parent and child classes, thereby limiting the reuse of child classes. This also reduces the inheritance hierarchies, which can become very difficult to deal with.
- Consider the operation of your application. Determine what metrics and operational data are required by the IT infrastructure to ensure the efficient deployment and operation of your application. Designing your application’s components and sub‐systems with a clear understanding of their individual operational requirements will significantly ease overall deployment and operation. Use automated QA tools during development to ensure that the correct operational data is provided by your application’s components and sub‐ systems.
Application Layers
- Separate the areas of concern. Break your application into distinct features that overlap in functionality as little as possible. The main benefit of this approach is that a feature or functionality can be optimized independently of other features or functionality. In addition, if one feature fails, it will not cause other features to fail as well, and they can run independently of one another. This approach also helps to make the application easier to understand and design, and facilitates management of complex interdependent systems.
- Be explicit about how layers communicate with each other. Allowing every layer in an application to communicate with or have dependencies upon all of the other layers will result in a solution that is more challenging to understand and manage. Make explicit decisions about the dependencies between layers and the data flow between them.
- Use abstraction to implement loose coupling between layers. This can be accomplished by defining interface components such as a façade with well known inputs and outputs that translate requests into a format understood by components within the layer. In addition, you can also use Interface types or abstract base classes to define a common interface or shared abstraction (dependency inversion) that must be implemented by interface components.
- Do not mix different types of components in the same logical layer. Start by identifying different areas of concern, and then group components associated with each area of concern into logical layers. For example, the UI layer should not contain business processing components, but instead should contain components used to handle user input and process user requests.
- Keep the data format consistent within a layer or component. Mixing data formats will make the application more difficult to implement, extend, and maintain. Every time you need to convert data from one format to another, you are required to implement translation code to perform the operation and incur a processing overhead.
Components, Modules, and Functions
- A component or an object should not rely on internal details of other components or objects. Each component or object should call a method of another object or component, and that method should have information about how to process the request and, if appropriate, how to route it to appropriate subcomponents or other components. This helps to create an application that is more maintainable and adaptable.
- Do not overload the functionality of a component. For example, a UI processing component should not contain data access code or attempt to provide additional functionality. Overloaded components often have many functions and properties providing business functionality mixed with crosscutting functionality such as logging and exception handling. The result is a design that is very error prone and difficult to maintain. Applying the single responsibility and separation of concerns principles will help you to avoid this.
- Understand how components will communicate with each other. This requires an understanding of the deployment scenarios your application must support. You must determine if all components will run within the same process, or if communication across physical or process boundaries must be supported—perhaps by implementing message‐based interfaces.
- Keep crosscutting code abstracted from the application business logic as far as possible. Crosscutting code refers to code related to security, communications, or operational management such as logging and instrumentation. Mixing the code that implements these functions with the business logic can lead to a design that is difficult to extend and maintain. Changes to the crosscutting code require touching all of the business logic code that is mixed with the crosscutting code. Consider using frameworks and techniques (such as aspect oriented programming) that can help to manage crosscutting concerns.
- Define a clear contract for components. Components, modules, and functions should define a contract or interface specification that describes their usage and behavior clearly. The contract should describe how other components can access the internal functionality of the component, module, or function; and the behavior of that functionality in terms of pre-conditions, post-conditions, side effects, exceptions, performance characteristics, and other factors.
Key Design Considerations¶
This guide describes the major decisions that you must make, and which help to ensure that you consider all of the important factors as you begin and then iteratively develop your architecture design. The major decisions, briefly described in the following sections, are:
- Determine the Application Type
- Determine the Deployment Strategy
- Determine the Appropriate Technologies
- Determine the Quality Attributes
- Determine the Crosscutting Concerns
For a more detailed description of the design process, see Chapter 4 "A Technique for Architecture and Design."
Determine the Application Type¶
Choosing the appropriate application type is the key part of the process of designing an application. Your choice is governed by your specific requirements and infrastructure limitations. Many applications must support multiple types of client, and may make use of more than one of the basic archetypes. This guide covers the following basic application types:
- Applications designed for mobile devices.
- Rich client applications designed to run primarily on a client PC.
- Rich Internet applications designed to be deployed from the Internet, which support rich UI and media scenarios.
- Service applications designed to support communication between loosely coupled components.
- Web applications designed to run primarily on the server in fully connected scenarios.
In addition, it provides information and guidelines for some more specialist application types. These include the following:
- Hosted and cloud-based applications and services.
- Office Business Applications (OBAs) that integrate Microsoft Office and Microsoft server technologies.
- SharePoint Line of Business (LOB) applications that provide portal style access to business information and functions.
Determine the Deployment Strategy¶
Your application may be deployed in a variety of environments, each with its own specific set of constraints such as physical separation of components across different servers, a limitation on networking protocols, firewall and router configurations, and more. Several common deployment patterns exist, which describe the benefits and considerations for a range of distributed and non-distributed scenarios. You must balance the requirements of the application with the appropriate patterns that the hardware can support, and the constraints that the environment exerts on your deployment options. These factors will influence your architecture design.
Determine the Appropriate Technologies¶
When choosing technologies for your application, the key factors to consider are the type of application you are developing and your preferred options for application deployment topology and architectural styles. Your choice of technologies will also be governed by organization policies, infrastructure limitations, resource skills, and so on. You must compare the capabilities of the technologies you choose against your application requirements, taking into account all of these factors before making decisions.
When designing to accommodate quality attributes, consider the following guidelines:
- Quality attributes are system properties that are separate from the functionality of the system.
- From a technical perspective, implementing quality attributes can differentiate a good system from a bad one.
- There are two types of quality attributes: those that are measured at run time, and those that can only be estimated through inspection.
- Analyze the tradeoffs between quality attributes.
Questions you should ask when considering quality attributes include:
- What are the key quality attributes required for your application? Identify them as part of the design process.
- What are the key requirements for addressing these attributes? Are they actually quantifiable?
- What are the acceptance criteria that will indicate that you have met the requirements?
Determine the Crosscutting Concerns¶
Crosscutting concerns represent key areas of your design that are not related to a specific layer in your application. For example, you should consider implementing centralized or common solutions for the following:
- A logging mechanism that allows each layer to log to a common store, or log to separate stores in such a way that the results can be correlated afterwards.
- A mechanism for authentication and authorization that passes identities across multiple layers to permit granting access to resources.
- An exception management framework that will work within each layer, and across the layers as exceptions are propagated to the system boundaries.
- A communication approach that you can use to communicate between the layers.
- A common caching infrastructure that allows you to cache data in the presentation layer, the business layer, and the data access layer.
The following list describes some of the key crosscutting concerns that you must consider when architecting your applications:
- Instrumentation and logging. Instrument all of the business-critical and system-critical events, and log sufficient details to recreate events in your system without including sensitive information.
- Authentication. Determine how to authenticate your users and pass authenticated identities across the layers.
- Authorization. Ensure proper authorization with appropriate granularity within each layer, and across trust boundaries.
- Exception management. Catch exceptions at functional, logical, and physical boundaries; and avoid revealing sensitive information to end users.
- Communication. Choose appropriate protocols, minimize calls across the network, and protect sensitive data passing over the network.
- Caching. Identify what should be cached, and where to cache, to improve your application’s performance and responsiveness. Ensure that you consider Web farm and application farm issues when designing caching.
Chapter 3: Architectural Patterns and Styles¶
Contents
- Overview
- Summary of Key Architectural Styles
- Client/Server Architectural Style
- Component-Based Architectural Style
- Domain Driven Design Architectural Style
- Layered Architectural Style
- Message-bus Architectural Style
- N-Tier / 3-Tier Architectural Style
- Object-Oriented Architectural Style
- Service-Oriented Architectural Style
- Additional Resources
Overview
This chapter describes and discusses high level patterns and principles commonly used for applications today. These are often referred to as the architectural styles, and include patterns such as client/server, layered architecture, component-based architecture, message bus architecture, and service-oriented architecture (SOA). For each style, you will find an overview, key principles, major benefits, and information that will help you choose the appropriate architectural styles for your application. It is important to understand that the styles describe different aspects of applications. For example, some architectural styles describe deployment patterns, some describe structure and design issues, and others describe communication factors. Therefore, a typical application will usually use a combination of more than one of the styles described in this chapter.
What Is An Architectural Style?
An architectural style, sometimes called an architectural pattern, is a set of principles—a coarse grained pattern that provides an abstract framework for a family of systems. An architectural style improves partitioning and promotes design reuse by providing solutions to frequently recurring problems. You can think of architecture styles and patterns as sets of principles that shape an application. Garlan and Shaw define an architectural style as:
“ߪa; family of systems in terms of a pattern of structural organization. More specifically, an architectural style determines the vocabulary of components and connectors that can be used in instances of that style, together with a set of constraints on how they can be combined. These can include topological constraints on architectural descriptions (e.g., no cycles). Other constraints—say, having to do with execution semantics—might also be part of the style definition.”
[David Garlan and Mary Shaw, January 1994, CMU-CS-94-166, see "An Introduction to Software Architecture" at http://www.cs.cmu.edu/afs/cs/project/able/ftp/intro_softarch/intro_softarch.pdf]
An understanding of architectural styles provides several benefits. The most important benefit is that they provide a common language. They also provide opportunities for conversations that are technology agnostic. This facilitates a higher level of conversation that is inclusive of patterns and principles, without getting into specifics. For example, by using architecture styles, you can talk about client/server versus n-tier. Architectural styles can be organized by their key focus area. The following table lists the major areas of focus and the corresponding architectural styles.
Category | Architecture styles |
---|---|
Communication | Service-Oriented Architecture (SOA), Message Bus |
Deployment | Client/Server, N-Tier, 3-Tier |
Domain | Domain Driven Design |
Structure | Component-Based, Object-Oriented, Layered Architecture |
Summary of Key Architectural Styles
The following table lists the common architectural styles described in this chapter. It also contains a brief description of each style. Later sections of this chapter contain more details of each style, as well as guidance to help you choose the appropriate ones for your application.
Architecture style | Description |
---|---|
Client/Server | Segregates the system into two applications, where the client makes requests to the server. In many cases, the server is a database with application logic represented as stored procedures. |
Component-Based Architecture | Decomposes application design into reusable functional or logical components that expose well-defined communication interfaces. |
Domain Driven Design | An object-oriented architectural style focused on modeling a business domain and defining business objects based on entities within the business domain. |
Layered Architecture | Partitions the concerns of the application into stacked groups (layers). |
Message Bus | An architecture style that prescribes use of a software system that can receive and send messages using one or more communication channels, so that applications can interact without needing to know specific details about each other. |
N-Tier / 3-Tier | Segregates functionality into separate segments in much the same way as the layered style, but with each segment being a tier located on a physically separate computer. |
Object-Oriented | A design paradigm based on division of responsibilities for an application or system into individual reusable and self-sufficient objects, each containing the data and the behavior relevant to the object. |
Service-Oriented Architecture (SOA) | Refers to applications that expose and consume functionality as a service using contracts and messages. |
Combining Architectural Styles
The architecture of a software system is almost never limited to a single architectural style, but is often a combination of architectural styles that make up the complete system. For example, you might have a SOA design composed of services developed using a layered architecture approach and an object-oriented architecture style.
A combination of architecture styles is also useful if you are building a public facing Web application, where you can achieve effective separation of concerns by using the layered architecture style. This will separate your presentation logic from your business logic and your data access logic. Your organization's security requirements might force you to deploy the application using either the 3-tier deployment approach, or a deployment of more than three tiers. The presentation tier may be deployed to the perimeter network, which sits between an organization's internal network and an external network. On your presentation tier, you may decide to use a separated presentation pattern (a type of layered design style), such as Model- View-Controller (MVC), for your interaction model. You might also choose a SOA architecture style, and implement message-based communication, between your Web server and application server.
If you are building a desktop application, you may have a client that sends requests to a program on the server. In this case, you might deploy the client and server using the client/server architecture style, and use the component-based architecture style to decompose the design further into independent components that expose the appropriate communication interfaces. Using the object-oriented design approach for these components will improve reuse, testability, and flexibility.
Many factors will influence the architectural styles you choose. These factors include the capacity of your organization for design and implementation; the capabilities and experience of your developers; and your infrastructure and organizational constraints. The following sections will help you to determine the appropriate styles for your applications.
Client/Server Architectural Style¶
The client/server architectural style describes distributed systems that involve a separate client and server system, and a connecting network. The simplest form of client/server system involves a server application that is accessed directly by multiple clients, referred to as a 2-Tier architectural style.
Historically, client/server architecture indicated a graphical desktop UI application that communicated with a database server containing much of the business logic in the form of stored procedures, or with a dedicated file server. More generally, however, the client/server architectural style describes the relationship between a client and one or more servers, where the client initiates one or more requests (perhaps using a graphical UI), waits for replies, and processes the replies on receipt. The server typically authorizes the user and then carries out the processing required to generate the result. The server may send responses using a range of protocols and data formats to communicate information to the client.
Today, some examples of the client/server architectural style include Web browser—based programs running on the Internet or an intranet; Microsoft Windows® operating system— based applications that access networked data services; applications that access remote data stores (such as e-mail readers, FTP clients, and database query tools); and tools and utilities that manipulate remote systems (such as system management tools and network monitoring tools).
Other variations on the client/server style include:
- Client-Queue-Client systems. This approach allows clients to communicate with other clients through a server-based queue. Clients can read data from and send data to a server that acts simply as a queue to store the data. This allows clients to distribute and synchronize files and information. This is sometimes known as a passive queue architecture.
- Peer-to-Peer (P2P) applications. Developed from the Client-Queue-Client style, the P2P style allows the client and server to swap their roles in order to distribute and synchronize files and information across multiple clients. It extends the client/server style through multiple responses to requests, shared data, resource discovery, and resilience to removal of peers.
- Application servers. A specialized architectural style where the server hosts and executes applications and services that a thin client accesses through a browser or specialized client installed software. An example is a client executing an application that runs on the server through a framework such as Terminal Services.
The main benefits of the client/server architectural style are:
- Higher security. All data is stored on the server, which generally offers a greater control of security than client machines.
- Centralized data access. Because data is stored only on the server, access and updates to the data are far easier to administer than in other architectural styles.
- Ease of maintenance. Roles and responsibilities of a computing system are distributed among several servers that are known to each other through a network. This ensures that a client remains unaware and unaffected by a server repair, upgrade, or relocation.
Consider the client/server architectural style if your application is server based and will support many clients, you are creating Web-based applications exposed through a Web browser, you are implementing business processes that will be used by people throughout the organization, or you are creating services for other applications to consume. The client/server architectural style is also suitable, like many networked styles, when you want to centralize data storage, backup, and management functions, or when your application must support different client types and different devices.
However, the traditional 2-Tier client/server architectural style has numerous disadvantages, including the tendency for application data and business logic to be closely combined on the server, which can negatively impact system extensibility and scalability, and its dependence on a central server, which can negatively impact system reliability. To address these issues, the client-server architectural style has evolved into the more general 3-Tier (or N-Tier) architectural style, described below, which overcomes some of the disadvantages inherent in the 2-Tier client-server architecture and provides additional benefits.
Component-Based Architectural Style¶
Component-based architecture describes a software engineering approach to system design and development. It focuses on the decomposition of the design into individual functional or logical components that expose well-defined communication interfaces containing methods, events, and properties. This provides a higher level of abstraction than object-oriented design principles, and does not focus on issues such as communication protocols and shared state.
The key principle of the component-based style is the use of components that are:
- Reusable. Components are usually designed to be reused in different scenarios in different applications. However, some components may be designed for a specific task.
- Replaceable. Components may be readily substituted with other similar components.
- Not context specific. Components are designed to operate in different environments and contexts. Specific information, such as state data, should be passed to the component instead of being included in or accessed by the component.
- Extensible. A component can be extended from existing components to provide new behavior.
- Encapsulated. Components expose interfaces that allow the caller to use its functionality, and do not reveal details of the internal processes or any internal variables or state.
- Independent. Components are designed to have minimal dependencies on other components. Therefore components can be deployed into any appropriate environment without affecting other components or systems.
Common types of components used in applications include user interface components such as grids and buttons (often referred to as controls), and helper and utility components that expose a specific subset of functions used in other components. Other common types of components are those that are resource intensive, not frequently accessed, and must be activated using the just-in-time (JIT) approach (common in remoting or distributed component scenarios); and queued components whose method calls may be executed asynchronously using message queuing and store and forward.
Components depend upon a mechanism within the platform that provides an environment in which they can execute, often referred to as component architecture. Examples are the component object model (COM) and the distributed component object model (DCOM) in Windows; and Common Object Request Broker Architecture (CORBA) and Enterprise JavaBeans ﴾EJB﴿ on other platforms. Component architectures manage the mechanics of locating components and their interfaces, passing messages or commands between components, and—in some cases—maintaining state.
However, the term component is often used in the more basic sense of a constituent part, element, or ingredient. The Microsoft .NET Framework provides support for building applications using such a component based approach. For example, this guide discusses business and data components, which are commonly code classes compiled into .NET Framework assemblies. They execute under the control of the .NET Framework runtime, and there may be more than one such component in each assembly.
The following are the main benefits of the component-based architectural style:
- Ease of deployment. As new compatible versions become available, you can replace existing versions with no impact on the other components or the system as a whole.
- Reduced cost. The use of third-party components allows you to spread the cost of development and maintenance.
- Ease of development. Components implement well-known interfaces to provide defined functionality, allowing development without impacting other parts of the system.
- Reusable. The use of reusable components means that they can be used to spread the development and maintenance cost across several applications or systems.
- Mitigation of technical complexity. Components mitigate complexity through the use of a component container and its services. Example component services include component activation, lifetime management, method queuing, eventing, and transactions.
Design patterns such as the Dependency Injection pattern or the Service Locator pattern can be used to manage dependencies between components, and promote loose coupling and reuse. Such patterns are often used to build composite applications that combine and reuse components across multiple applications.
Consider the component-based architectural style if you already have suitable components or can obtain suitable components from third-party suppliers; your application will predominantly execute procedural-style functions, perhaps with little or no data input; or you want to be able to combine components written in different code languages. Also, consider this style if you want to create a pluggable or composite architecture that allows you to easily replace and update individual components.
Domain Driven Design Architectural Style¶
Domain Driven Design (DDD) is an object-oriented approach to designing software based on the business domain, its elements and behaviors, and the relationships between them. It aims to enable software systems that are a realization of the underlying business domain by defining a domain model expressed in the language of business domain experts. The domain model can be viewed as a framework from which solutions can then be rationalized.
To apply Domain Driven Design, you must have a good understanding of the business domain you want to model, or be skilled in acquiring such business knowledge. The development team will often work with business domain experts to model the domain. Architects, developers, and subject matter experts have diverse backgrounds, and in many environments will use different languages to describe their goals, designs and requirements. However, within Domain Driven Design, the whole team agrees to only use a single language that is focused on the business domain, and which excludes any technical jargon.
As the core of the software is the domain model, which is a direct projection of this shared language, it allows the team to quickly find gaps in the software by analyzing the language around it. The creation of a common language is not merely an exercise in accepting information from the domain experts and applying it. Quite often, communication problems within development teams are due not only to misunderstanding the language of the domain, but also due to the fact that the domain's language is itself ambiguous. The Domain Driven Design process holds the goal not only of implementing the language being used, but also improving and refining the language of the domain. This in turn benefits the software being built, since the model is a direct projection of the domain language.
In order to help maintain the model as a pure and helpful language construct, you must typically implement a great deal of isolation and encapsulation within the domain model. Consequently, a system based on Domain Driven Design can come at a relatively high cost. While Domain Driven Design provides many technical benefits, such as maintainability, it should be applied only to complex domains where the model and the linguistic processes provide clear benefits in the communication of complex information, and in the formulation of a common understanding of the domain.
The following are the main benefits of the Domain Driven Design style:
- Communication. All parties within a development team can use the domain model and the entities it defines to communicate business knowledge and requirements using a common business domain language, without requiring technical jargon.
- Extensible. The domain model is often modular and flexible, making it easy to update and extend as conditions and requirements change.
- Testable. The domain model objects are loosely coupled and cohesive, allowing them to be more easily tested.
Consider DDD if you have a complex domain and you wish to improve communication and understanding within your development team, or where you must express the design of an application in a common language that all stakeholders can understand. DDD can also be an ideal approach if you have large and complex enterprise data scenarios that are difficult to manage using other techniques.
Layered Architectural Style¶
Layered architecture focuses on the grouping of related functionality within an application into distinct layers that are stacked vertically on top of each other. Functionality within each layer is related by a common role or responsibility. Communication between layers is explicit and loosely coupled. Layering your application appropriately helps to support a strong separation of concerns that, in turn, supports flexibility and maintainability.
The layered architectural style has been described as an inverted pyramid of reuse where each layer aggregates the responsibilities and abstractions of the layer directly beneath it. With strict layering, components in one layer can interact only with components in the same layer or with components from the layer directly below it. More relaxed layering allows components in a layer to interact with components in the same layer or with components in any lower layer.
The layers of an application may reside on the same physical computer (the same tier) or may be distributed over separate computers (n-tier), and the components in each layer communicate with components in other layers through well-defined interfaces. For example, a typical Web application design consists of a presentation layer (functionality related to the UI), a business layer (business rules processing), and a data layer (functionality related to data access, often almost entirely implemented using high-level data access frameworks). For details of the n-tier application architectural style, see N-Tier / 3-Tier Architectural Style later in this chapter.
Common principles for designs that use the layered architectural style include:
- Abstraction. Layered architecture abstracts the view of the system as whole while providing enough detail to understand the roles and responsibilities of individual layers and the relationship between them.
- Encapsulation. No assumptions need to be made about data types, methods and properties, or implementation during design, as these features are not exposed at layer boundaries.
- Clearly defined functional layers. The separation between functionality in each layer is clear. Upper layers such as the presentation layer send commands to lower layers, such as the business and data layers, and may react to events in these layers, allowing data to flow both up and down between the layers.
- High cohesion. Well-defined responsibility boundaries for each layer, and ensuring that each layer contains functionality directly related to the tasks of that layer, will help to maximize cohesion within the layer.
- Reusable. Lower layers have no dependencies on higher layers, potentially allowing them to be reusable in other scenarios.
- Loose coupling. Communication between layers is based on abstraction and events to provide loose coupling between layers.
Examples of layered applications include line-of-business (LOB) applications such as accounting and customer-management systems; enterprise Web-based applications and Web sites, and enterprise desktop or smart clients with centralized application servers for business logic.
A number of design patterns support the layered architectural style. For example, Separated Presentation patterns encompass a range of patterns that the handling of the user's interactions from the UI, the presentation and business logic, and the application data with which the user works. Separated Presentation allows graphical designers to create a UI while developers generate the code to drive it. Dividing the functionality into separate roles in this way provides increased opportunities to test the behavior of individual roles. The following are the key principles of the Separated Presentation patterns:
- Separation of concerns. Separated Presentation patterns divide UI processing concerns into distinct roles; for example, MVC has three roles: the Model, the View, and the Controller. The Model represents data (perhaps a domain model that includes business rules); the View represents the UI; and the Controller handles requests, manipulates the model, and performs other operations.
- Event-based notification. The Observer pattern is commonly used to provide notifications to the View when data managed by the Model changes.
- Delegated event handling. The controller handles events triggered from the UI controls in the View.
Other examples of Separated Presentation patterns are the Passive View pattern and the Supervising Presenter (or Supervising Controller) pattern. The main benefits of the layered architectural style, and the use of a Separated Presentation pattern, are:
- Abstraction. Layers allow changes to be made at the abstract level. You can increase or decrease the level of abstraction you use in each layer of the hierarchical stack.
- Isolation. Allows you to isolate technology upgrades to individual layers in order to reduce risk and minimize impact on the overall system.
- Manageability. Separation of core concerns helps to identify dependencies, and organizes the code into more manageable sections.
- Performance. Distributing the layers over multiple physical tiers can improve scalability, fault tolerance, and performance.
- Reusability. Roles promote reusability. For example, in MVC, the Controller can often be reused with other compatible Views in order to provide a role sp customized view on to the same data and functionality.
- Testability. Increased testability arises from having well-defined layer interfaces, as well as the ability to switch between different implementations of the l Presentation patterns allow you to build mock objects that mimic the behavior of concrete objects such as the Model, Controller, or View during testing.
Consider the layered architectural style if you have existing layers that are suitable for reuse in other applications, you already have applications that expose suitable business processes through service interfaces, or your application is complex and the high-level design demands separation so that teams can focus on different areas of functionality. The layered architectural style is also appropriate if your application must support different client types and different devices, or you want to implement complex and/or configurable business rules and processes.
Consider a Separated Presentation pattern if you want improved testability and simplified maintenance of UI functionality, or you want to separate the task of designing the UI from the development of the logic code that drives it. These patterns are also appropriate when your UI view does not contain any request processing code, and does not implement any business logic.
Message Bus Architectural Style¶
Message bus architecture describes the principle of using a software system that can receive and send messages using one or more communication channels, so that applications can interact without needing to know specific details about each other. It is a style for designing applications where interaction between applications is accomplished by passing messages (usually asynchronously) over a common bus. The most common implementations of message bus architecture use either a messaging router or a Publish/Subscribe pattern, and are often implemented using a messaging system such as Message Queuing. Many implementations consist of individual applications that communicate using common schemas and a shared infrastructure for sending and receiving messages. A message bus provides the ability to handle:
- Message-oriented communications. All communication between applications is based on messages that use known schemas.
- Complex processing logic. Complex operations can be executed by combining a set of smaller operations, each of which supports specific tasks, as part of a multistep itinerary.
- Modifications to processing logic. Because interaction with the bus is based on common schemas and commands, you can insert or remove applications on the bus to change the logic that is used to process messages.
- Integration with different environments. By using a message-based communication model based on common standards, you can interact with applications developed for different environments, such as Microsoft .NET and Java.
Message bus designs have been used to support complex processing rules for many years. The design provides a pluggable architecture that allows you to insert applications into the process, or improve scalability by attaching several instances of the same application to the bus. Variations on the message bus style include:
- Enterprise Service Bus (ESB). Based on message bus designs, an ESB uses services for communication between the bus and components attached to the bus. An ESB will usually provide services that transform messages from one format to another, allowing clients that use incompatible message formats to communicate with each other
- Internet Service Bus (ISB). This is similar to an enterprise service bus, but with applications hosted in the cloud instead of on an enterprise network. A core concept of ISB is the use of Uniform Resource Identifiers (URIs) and policies to control the routing of logic through applications and services in the cloud.
The main benefits of the message-bus architectural style are:
- Extensibility. Applications can be added to or removed from the bus without having an impact on the existing applications.
- Low complexity. Application complexity is reduced because each application only needs to know how to communicate with the bus.
- Flexibility. The set of applications that make up a complex process, or the communication patterns between applications, can be changed easily to match changes in business or user requirements, simply through changes to the configuration or parameters that control routing.
- Loose coupling. As long as applications expose a suitable interface for communication with the message bus, there is no dependency on the application itself, allowing changes, updates, and replacements that expose the same interface.
- Scalability. Multiple instances of the same application can be attached to the bus in order to handle multiple requests at the same time.
- Application simplicity. Although a message bus implementation adds complexity to the infrastructure, each application needs to support only a single connection to the message bus instead of multiple connections to other applications.
Consider the message bus architectural style if you have existing applications that interoperate with each other to perform tasks, or you want to combine multiple tasks into a single operation. This style is also appropriate if you are implementing a task that requires interaction with external applications, or applications hosted in different environments.
N-Tier / 3-Tier Architectural Style¶
N-tier and 3-tier are architectural deployment styles that describe the separation of functionality into segments in much the same way as the layered style, but with each segment being a tier that can be located on a physically separate computer. They evolved through the component-oriented approach, generally using platform specific methods for communication instead of a message-based approach.
N-tier application architecture is characterized by the functional decomposition of applications, service components, and their distributed deployment, providing improved scalability, availability, manageability, and resource utilization. Each tier is completely independent from all other tiers, except for those immediately above and below it. The nth tier only has to know how to handle a request from the n+1th tier, how to forward that request on to the n-1th tier (if there is one), and how to handle the results of the request. Communication between tiers is typically asynchronous in order to support better scalability.
N-tier architectures usually have at least three separate logical parts, each located on a separate physical server. Each part is responsible for specific functionality. When using a layered design approach, a layer is deployed on a tier if more than one service or application is dependent on the functionality exposed by the layer.
An example of the N-tier/3-tier architectural style is a typical financial Web application where security is important. The business layer must be deployed behind a firewall, which forces the deployment of the presentation layer on a separate tier in the perimeter network. Another example is a typical rich client connected application, where the presentation layer is deployed on client machines and the business layer and data access layer are deployed on one or more server tiers.
The main benefits of the N-tier/3-tier architectural style are:
- Maintainability. Because each tier is independent of the other tiers, updates or changes can be carried out without affecting the application as a whole.
- Scalability. Because tiers are based on the deployment of layers, scaling out an application is reasonably straightforward.
- Flexibility. Because each tier can be managed or scaled independently, flexibility is increased.
- Availability. Applications can exploit the modular architecture of enabling systems using easily scalable components, which increases availability.
Consider either the N-tier or the 3-tier architectural style if the processing requirements of the layers in the application differ such that processing in one layer could absorb sufficient resources to slow the processing in other layers, or if the security requirements of the layers in the application differ. For example, the presentation layer should not store sensitive data, while this may be stored in the business and data layers. The N-tier or the 3-tier architectural style is also appropriate if you want to be able to share business logic between applications, and you have sufficient hardware to allocate the required number of servers to each tier.
Consider using just three tiers if you are developing an intranet application where all servers are located within the private network; or an Internet application where security requirements do not restrict the deployment of business logic on the public facing Web or application server. Consider using more than three tiers if security requirements dictate that business logic cannot be deployed to the perimeter network, or the application makes heavy use of resources and you want to offload that functionality to another server
Object-Oriented Architectural Style¶
Object-oriented architecture is a design paradigm based on the division of responsibilities for an application or system into individual reusable and self-sufficient objects, each containing the data and the behavior relevant to the object. An object-oriented design views a system as a series of cooperating objects, instead of a set of routines or procedural instructions. Objects are discrete, independent, and loosely coupled; they communicate through interfaces, by calling methods or accessing properties in other objects, and by sending and receiving messages. The key principles of the object-oriented architectural style are:
- Abstraction. This allows you to reduce a complex operation into a generalization that retains the base characteristics of the operation. For example, an abstract interface can be a well-known definition that supports data access operations using simple methods such as Get and Update. Another form of abstraction could be metadata used to provide a mapping between two formats that hold structured data.
- Composition. Objects can be assembled from other objects, and can choose to hide these internal objects from other classes or expose them as simple interfaces.
- Inheritance. Objects can inherit from other objects, and use functionality in the base object or override it to implement new behavior. Moreover, inheritance makes maintenance and updates easier, as changes to the base object are propagated automatically to the inheriting objects.
- Encapsulation. Objects expose functionality only through methods, properties, and events, and hide the internal details such as state and variables from other objects. This makes it easier to update or replace objects, as long as their interfaces are compatible, without affecting other objects and code.
- Polymorphism. This allows you to override the behavior of a base type that supports operations in your application by implementing new types that are interchangeable with the existing object.
- Decoupling. Objects can be decoupled from the consumer by defining an abstract interface that the object implements and the consumer can understand. This allows you to provide alternative implementations without affecting consumers of the interface.
Common uses of the object-oriented style include defining an object model that supports complex scientific or financial operations, and defining objects that represent real world artifacts within a business domain (such as a customer or an order). The latter is a process commonly implemented using the more specialized domain driven design style, which takes advantage of the principles of the object-oriented style. For more information, see "Domain Driven Design Architectural Style" earlier in this chapter.
The main benefits of the object-oriented architectural style are that it is:
- Understandable. It maps the application more closely to the real world objects, making it more understandable.
- Reusable. It provides for reusability through polymorphism and abstraction.
- Testable. It provides for improved testability through encapsulation.
- Extensible. Encapsulation, polymorphism, and abstraction ensure that a change in the representation of data does not affect the interfaces that the object exposes, which would limit the capability to communicate and interact with other objects.
- Highly Cohesive. By locating only related methods and features in an object, and using different objects for different sets of features, you can achieve a high level of cohesion.
Consider the object-oriented architectural style if you want to model your application based on real world objects and actions, or you already have suitable objects and classes that match the design and operational requirements. The object-oriented style is also suitable if you must encapsulate logic and data together in reusable components or you have complex business logic that requires abstraction and dynamic behavior.
Service-Oriented Architectural Style¶
Service-oriented architecture (SOA) enables application functionality to be provided as a set of services, and the creation of applications that make use of software services. Services are loosely coupled because they use standards-based interfaces that can be invoked, published, and discovered. Services in SOA are focused on providing a schema and message-based interaction with an application through interfaces that are application scoped, and not component or object-based. An SOA service should not be treated as a component-based service provider.
The SOA style can package business processes into interoperable services, using a range of protocols and data formats to communicate information. Clients and other services can access local services running on the same tier, or access remote services over a connecting network.
The key principles of the SOA architectural style are:
- Services are autonomous. Each service is maintained, developed, deployed, and versioned independently.
- Services are distributable. Services can be located anywhere on a network, locally or remotely, as long as the network supports the required communication protocols.
- Services are loosely coupled. Each service is independent of others, and can be replaced or updated without breaking applications that use it as long as the interface is still compatible.
- Services share schema and contract, not class. Services share contracts and schemas when they communicate, not internal classes.
- Compatibility is based on policy. Policy in this case means definition of features such as transport, protocol, and security.
Common examples of service-oriented applications include sharing information, handling multistep processes such as reservation systems and online stores, exposing industry specific data or services over an extranet, and creating mashups that combine information from multiple sources.
The main benefits of the SOA architectural style are:
- Domain alignment. Reuse of common services with standard interfaces increases business and technology opportunities and reduces cost.
- Abstraction. Services are autonomous and accessed through a formal contract, which provides loose coupling and abstraction.
- Discoverability. Services can expose descriptions that allow other applications and services to locate them and automatically determine the interface.
- Interoperability. Because the protocols and data formats are based on industry standards, the provider and consumer of the service can be built and deployed on different platforms.
- Rationalization. Services can be granular in order to provide specific functionality, rather than duplicating the functionality in number of applications, which removes duplication.
Consider the SOA style if you have access to suitable services that you wish to reuse; can purchase suitable services provided by a hosting company; want to build applications that compose a variety of services into a single UI; or you are creating Software plus Services (S+S), Software as a Service (SaaS), or cloud-based applications. The SOA style is suitable when you must support message-based communication between segments of the application and expose functionality in a platform independent way, when you want to take advantage of federated services such as authentication, or you want to expose services that are discoverable through directories and can be used by clients that have no prior knowledge of the interfaces.
Chapter 4: A Technique for Architecture and Design¶
Contents
- Overview
- Inputs, Outputs, and Design Steps
- Identify Architecture Objectives
- Key Scenarios
- Application Overview
- Key Issues
- Candidate Solutions
- What to Do Next
- Reviewing Your Architecture
- Representing and Communicating Your Architecture Design
Overview
This chapter describes an iterative technique that you can use to think about and sketch out your potential architecture. It will help you to bring together the key decisions discussed in this guide; including quality attributes, architecture styles, application types, technologies, and deployment decisions.
The technique includes a series of five main steps, each of which breaks down into individual considerations explained throughout the remainder of the guide. The iterative process will help you to produce candidate solutions that you can further refine by repeating the steps, finally creating an architecture design that best fits your application. At the end of the process, you can review and communicate your architecture to all interested parties.
Depending on your organization's approach to software development, you may revisit your architecture many times during the lifetime of a project. You can use this technique to refine your architecture further, building on what you have learned in the intervening period of spiking, prototyping, and actual development.
It is also important to realize that this is just one possible approach. There are many other more formal approaches to defining, reviewing, and communicating your architecture. Some are discussed briefly at the end of this chapter.
Inputs, Outputs, and Design Steps¶
The inputs to your design can help you to formalize the requirements and constraints that your architecture must accommodate. Common inputs are use cases and usage scenarios, functional requirements, non-functional requirements (including quality attributes such as performance, security, reliability, and others), technological requirements, the target deployment environment, and other constraints.
During the design process, you will create a list of the architecturally significant use cases, the architecture issues that require special attention, and the candidate architecture solutions that satisfy the requirements and constraints defined in the design process. A common technique for refining the design over time, until it satisfies all of the requirements and adheres to all of the constraints, is an iterative technique consisting of the five major stages shown in Figure 1.
Figure 1
The iterative steps for core architecture design activities
The steps, described in more detail in the following sections, are:
- Identify Architecture Objectives. Clear objectives help you to focus on your architecture and on solving the right problems in your design. Precise objectives help you to determine when you have completed the current phase, and when you are ready to move to the next phase.
- Key Scenarios. Use key scenarios to focus your design on what matters most, and to evaluate your candidate architectures when they are ready.
- Application Overview. Identify your application type, deployment architecture, architecture styles, and technologies in order to connect your design to the real world in which the application will operate.
- Key Issues. Identify key issues based on quality attributes and crosscutting concerns. These are the areas where mistakes are most often made when designing an application.
- Candidate Solutions. Create an architecture spike or prototype that evolves and improves the solution and evaluate it against your key scenarios, issues, and deployment constraints before beginning the next iteration of your architecture.
This architectural process is meant to be an iterative and incremental approach. Your first candidate architecture will be a high-level design that you can test against key scenarios, requirements, known constraints, quality attributes, and the architecture frame. As you refine your candidate architecture, you will learn more details about the design and will be able to further expand key scenarios, your application overview, and your approach to issues.
When taking an iterative approach to architecture, it is often tempting to iterate on horizontal slices (layers) of the application rather than vertical slices that require you to think about functionality across layers that comprise a complete feature (use case) for users. If you fail to iterate vertically, you run the risk of implementing a great deal of functionality before your users can validate it.
You should not try to build your architecture in a single iteration. Each iteration should add more detail. Do not get lost in the details, but instead focus on the major steps and build a framework on which you can base your architecture and design. The following sections provide guidelines and information on each of the steps.
Identify Architecture Objectives¶
Architecture objectives are the goals and constraints that shape your architecture and design process, scope the exercise, and help you determine when you are finished. Consider the following key points as you identify your architecture objectives:
- Identify your architecture goals at the start. The amount of time you spend in each phase of architecture and design will depend on these goals. For example, are you building a prototype, testing potential paths, or embarking on a long-running architectural process for a new application?
- Identify who will consume your architecture. Determine if your design will be used by other architects, or made available to developers and testers, operations staff, and management. Consider the needs and experience of your audience to make your resulting design more accessible to them.
- Identify your constraints. Understand your technology options and constraints, usage constraints, and deployment constraints. Understand your constraints at the start so that you do not waste time or encounter surprises later in your application development process.
Scope and Time¶
Based on the high-level goals for your architecture, you can scope the amount of time to spend on each of your design activities. For example, a prototype might only require a few days to design, while a complete and fully detailed architecture for a complex application could potentially take months to complete—and may involve architecture and design over many iterations. Use your understanding of the objectives to determine how much time and energy to spend on each step, to gain an understanding of what the outcome will look like, and to define clearly the purpose and priorities of your architecture. Possible purposes might include:
- Creating a complete application design.
- Building a prototype.
- Identifying key technical risks.
- Testing potential options.
- Building shared models to gain an understanding of the system.
Each of these will result in a different emphasis on design, and a varying time commitment. For example, if you want to identify key risks in your authentication architecture, you will spend much of your time and energy identifying authentication scenarios, constraints on your authentication architecture, and possible authentication technology choices. However, if you are in the early stages of considering the overall architecture for an application, authentication will be only one of many other concerns for which you address and document solutions.
Some examples of architecture activities are building a prototype to get feedback on the order-processing UI for a Web application, testing different ways to map location data to search results, building a customer order-tracking application, and designing the authentication and authorization architecture for an application in order to perform a security review.
Key Scenarios¶
In the context of architecture and design, a use case is a description of a set of interactions between the system and one or more actors (either a user or another system). A scenario is a broader and more encompassing description of a user's interaction with the system, rather than a path through a use case. When thinking about the architecture of your system, the goal should be to identify several key scenarios that will help you to make decisions about your architecture. The goal is to achieve a balance between the user, business, and system goals (as shown in Figure 1 of Chapter 1 "What is Software Architecture?").
Key scenarios are those that are considered the most important scenarios for the success of your application. Key scenarios can be defined as any scenario that meets one or more of the following criteria:
- It represents an issue—a significant unknown area or an area of significant risk.
- It refers to an architecturally significant use case (described in the following section).
- It represents the intersection of quality attributes with functionality.
- It represents a tradeoff between quality attributes.
For example, your scenarios covering user authentication may be key scenarios because they are an intersection of a quality attribute (security) with important functionality (how a user logs into your system). Another example would be a scenario that centered on an unfamiliar or new technology.
Architecturally Significant Use Cases¶
Architecturally significant use cases have an impact on many aspects of your design. These use cases are especially important in shaping the success of your application. They are important for the acceptance of the deployed application, and they must exercise enough of the design to be useful in evaluating the architecture. Architecturally significant use cases are:
- Business Critical. The use case has a high usage level or is particularly important to users or other stakeholders when compared to other features, or it implies high risk.
- High Impact. The use case intersects with both functionality and quality attributes, or represents a crosscutting concern that has an end-to-end impact across the layer and tiers of your application. An example might be a Create, Read, Update, Delete (CRUD) operation that is security-sensitive.
After you have determined the architecturally significant use cases for your application, you can use them as a way to evaluate the success or failure of candidate architectures. If the candidate architecture addresses more use cases, or addresses existing use cases more effectively, it will help usually indicate that this candidate architecture is an improvement over the baseline architecture. For a definition of the term use case, see "What is a Use Case?" at http://searchsoftwarequality.techtarget.com/sDefinition/0,,sid92_gci334062,00.html.
A good use case will intersect the user view, the system view, and the business view of the architecture. Use these scenarios and use cases to test your design and determine where any issues may be. Consider the following when thinking about your use cases and scenarios:
- Early in the project, reduce risk by creating a candidate architecture that supports architecturally significant end-to-end scenarios that exercise all layers of the architecture.
- Using your architecture model as a guide, make changes to your architecture, design, and code to meet your scenarios, functional requirements, technological requirements, quality attributes, and constraints.
- Create an architecture model based on what you know at the time, and define a list of questions that must be addressed in subsequent stories and iterations.
- After you make sufficient significant changes to the architecture and design, consider creating a use case that reflects and exercises these changes.
Application Overview¶
Create an overview of what your application will look like when it is complete. This overview serves to make your architecture more tangible, connecting it to real-world constraints and decisions. An application overview consists of the following activities:
- Determine your application type. First, determine what type of application you are building. Is it a mobile application, a rich client, a rich Internet application, a service, a Web application, or some combination of these types? For more details of the common application archetypes, see Chapter 20 "Choosing an Application Type."
- Identify important architecture design styles. Determine which architecture styles you will be using in your design. An architecture style is a set of principles. You can think of it as a coarse-grained pattern that provides an abstract framework for a family of systems. Each style defines a set of rules that specify the kinds of components you can use to assemble a system, the kinds of relationships used in their assembly, constraints on the way they are assembled, and assumptions about the meaning of how you put them together. An architecture style improves partitioning and promotes design reuse by providing solutions to frequently recurring problems. Common architectural styles are Service Oriented Architecture (SOA), client/server, layered, message-bus, and domain-driven design. Applications will often use a combination of styles. For more information about the architectural styles in common use today, see Chapter 3 "Architectural Patterns and Styles."
- Determine relevant technologies. Finally, identify the relevant technology choices based on your application type and other constraints, and determine which technologies you will use in your design. Key factors to consider are the type of application you are developing, and your preferred options for application deployment topology and architectural styles. The choice of technologies will also be governed by organization policies, infrastructure limitations, resource skills, and so on. The following section describes some of the common Microsoft technologies for each type of application.
Relevant Technologies¶
When choosing the technologies you will use in your design, consider which will help you to support your chosen architectural styles, your chosen application type, and the key quality attributes for your application. For example, for the Microsoft platform, the following list will help you understand which presentation, implementation, and communication technologies are most suited to each type of application:
- Mobile Applications. You can use presentation-layer technologies such as the .NET Compact Framework, ASP.NET for Mobile, and Silverlight for Mobile to develop applications for mobile devices.
- Rich Client Applications. You can use combinations of Windows Presentation Foundation (WPF), Windows Forms, and XAML Browser Application (XBAP) presentation-layer technologies to develop applications with rich UIs that are deployed and run on the client.
- Rich Internet Client Applications ﴾RIA﴿. You can use the Microsoft Silverlight™ browser plug‐in, or Silverlight combined with AJAX, to deploy rich UI experiences within a Web browser.
- Web Applications. You can use ASP.NET Web Forms, AJAX, Silverlight controls, ASP.NET MVC, and ASP.NET Dynamic data to create Web applications.
- Service Applications. You can use Windows Communication Foundation (WCF) and ASP.NET Web services (ASMX) to create services that expose functionality to external systems and service consumers.
Whiteboard Your Architecture¶
It is important that you are able to whiteboard your architecture. Whether you share your whiteboard on paper, slides, or through another format, the key is to show the major constraints and decisions in order to frame and start conversations. The value is actually twofold. If you cannot whiteboard the architecture then it suggests that it is not well understood. If you can provide a clear and concise whiteboard diagram, others will understand it and you can communicate details to them more easily.
Figure 2
Example of an architecture whiteboard showing a high-level design for a Web application indicating the protocols and authentication methods it will use.
Key Issues¶
Identify the issues in your application architecture to understand the areas where mistakes are most likely to be made. Potential issues include the appearance of new technologies, and critical business requirements. For example, "Can I swap from one third party service to another?," "Can I add support for a new client type?," "Can I quickly change my business rules relating to billing?," and "Can I migrate to a new technology for X?" While these factors are extremely generalized, they (and other areas of risk) generally map in implementation terms to quality attributes and crosscutting concerns.
Quality Attributes¶
Quality attributes are the overall features of your architecture that affect run-time behavior, system design, and user experience. The extent to which the application possesses a desired combination of quality attributes such as usability, performance, reliability, and security indicates the success of the design and the overall quality of the software application. When designing applications to meet any of these qualities, it is necessary to consider the impact on other requirements; you must analyze the tradeoffs between multiple quality attributes. The importance or priority of each quality attribute differs from system to system; for example, in a line-of-business (LOB) system, performance, scalability, security, and usability will be more important than interoperability. Interoperability is likely to be far more important in a shrink-wrap application than in a LOB application.
Quality attributes represent areas of concern that have the potential for application-wide impact across layers and tiers. Some attributes are related to the overall system design, while others are specific to run-time, design-time, or user-centric issues. Use the following list to help you organize your thinking about the quality attributes, and to understand which scenarios they are most likely to affect:
- System qualities. The overall qualities of the system when considered as a whole; such as supportability and testability.
- Run-time qualities. The qualities of the system directly expressed at run-time; such as availability, interoperability, manageability, performance, reliability, scalability, and security.
- Design qualities. The qualities reflecting the design of the system; such as conceptual integrity, flexibility, maintainability, and reusability.
- User qualities. The usability of the system
Crosscutting Concerns¶
Crosscutting concerns are the features of your design that may apply across all layers, components, and tiers. These are also the areas in which high-impact design mistakes are most often made. Examples of crosscutting concerns are:
- Authentication and Authorization. How you choose appropriate authentication and authorization strategies, flow identity across layers and tiers, and store user identities.
- Caching. How you choose an appropriate caching technology, determine what data to cache, where to cache the data, and a suitable expiration policy.
- Communication. How you choose appropriate protocols for communication across layers and tiers, design loose coupling across layers, perform asynchronous communication, and pass sensitive data.
- Configuration Management. How you determine what information must be configurable, where and how to store configuration information, how to protect sensitive configuration information, and how to handle configuration information in a farm or cluster.
- Exception Management. How you handle and log exceptions, and provide notification when required.
- Logging and Instrumentation. How you determine which information to log, how to make the logging configurable, and determine what level of instrumentation is required.
- Validation. How you determine where and how to perform validation; the techniques you choose for validating on length, range, format, and type; how you constrain and reject input invalid values; how you sanitize potentially malicious or dangerous input; and how you can define and reuse validation logic across your application's layers and tiers.
Designing for Issue Mitigation¶
By analyzing quality attributes and crosscutting concerns in relation to your design requirements, you can focus on specific areas of concern. For example, the quality attribute Security is obviously a vital factor in your design, and applies at many levels and areas of the architecture. The relevant crosscutting concerns for security provide guidance on specific areas where you should focus your attention. You can use the individual crosscutting categories to divide your application architecture for further analysis, and to help you identify application vulnerabilities. This approach leads to a design that optimizes security aspects. Questions you might consider when examining the crosscutting concerns for security are:
- Auditing and Logging. Who did what and when? Is the application operating normally? Auditing refers to how your application records security-related events. Logging refers to how your application publishes information about its operation.
- Authentication. Who are you? Authentication is the process where one entity definitively establishes the identity of another entity, typically with credentials such as a username and password.
- Authorization. What can you do? Authorization refers to how your application controls access to resources and operations.
- Configuration Management. What context does your application run under? Which databases does it connect to? How is your application administered? How are these settings protected? Configuration management refers to how your application handles these operations and issues.
- Cryptography. How are you handling secrets (confidentiality)? How are you tamper-proofing your data or libraries (integrity)? How are seeding random values that must be cryptographically strong? Cryptography refers to how your application enforces confidentiality and integrity.
- Exception Management. When a method call in your application fails, what does your application do? How much information does it reveal? Does it return friendly error messages to end users? Does it pass valuable exception information back to the calling code? Does it fail gracefully? Does it help administrators to perform root cause analysis of the fault? Exception management refers to how you handle exceptions within your application.
- Input and Data Validation. How do you know that the input your application receives is valid and safe? Does it constrain input through entry points and encode output through exit points. Can it trust data sources such as databases and file shares? Input validation refers to how your application filters, scrubs, or rejects input before additional processing.
- Sensitive data. How does your application handle sensitive data? Does it protect confidential user and application data? Sensitive data refers to how your application handles any data that must be protected either in memory, over the network, or in persistent stores.
- Session Management. How does your application handle and protect user sessions? A session refers to a set of related interactions between a user and your application.
You can use these questions and answers to make key security design decisions for your application, and document these are part of your architecture. For example, Figure 3 shows the security issues identified in a typical Web application architecture.
Figure 3
Security issues identified in a typical Web application architecture.
Candidate Solutions¶
After you define the key issues, you can create your initial baseline architecture and then start to fill in the details to produce a candidate architecture. Along the way, you may use architectural spikes to explore specific areas of the design or to validate new concepts. You then validate your new candidate architecture against the key scenarios and requirements you have defined, before iteratively following the cycle and improving the design.
::: tip Note It is important, especially if your design and development is following an agile process, that your iteration encompass both architecture and development activities. This avoids the big design up front approach. :::
It is important, especially if your design and development is following an agile process, that your iteration encompass both architecture and development activities. This avoids the big design up front approach.
Baseline and Candidate Architectures¶
A baseline architecture describes the existing system —it is how your system looks today. If this is a new architecture, your initial baseline is the first high‐level architectural design from which candidate architectures will be built. A candidate architecture includes the application type, the deployment architecture, the architectural style, technology choices, quality attributes, and crosscutting concerns.
As you evolve the design, ensure that at each stage you understand the key risks and adapt your design to reduce them, optimize for effective and efficient communication of design information, and build your architecture with flexibility and refactoring in mind. You may need to modify your architecture a number of times, through several iterations, candidate architectures, and by using multiple architectural spikes. If the candidate architecture is an improvement, it can become the baseline from which new candidate architectures can be created and tested.
This iterative and incremental approach allows you to get the big risks out of the way first, iteratively render your architecture, and use architectural tests to prove that each new baseline is an improvement over the last. Consider the following questions to help you test a new candidate architecture that results from an architectural spike:
- Does this architecture succeed without introducing any new risks?
- Does this architecture mitigate more known risks than the previous iteration?
- Does this architecture meet additional requirements?
- Does this architecture enable architecturally significant use cases?
- Does this architecture address quality attribute concerns?
- Does this architecture address additional crosscutting concerns?
Architectural Spikes¶
An architectural spike is a test implementation of a small part of the application's overall design or architecture. The purpose is to analyze a technical aspect of a specific piece of the solution in order to validate technical assumptions, choose between potential designs and implementation strategies, or sometimes to estimate implementation timescales.
Architectural spikes are often used as part of agile or extreme programming development approaches but can be a very effective way to refine and evolve a solution's design regardless of the development approach adopted. By focusing on key parts of the solution's overall design, architectural spikes can be used to resolve important technical challenges and to reduce overall risk and uncertainty in the solution's design.
What to Do Next¶
After you complete the architecture-modeling activity, you can begin to refine the design, plan tests, and communicate the design to others. Keep in mind the following guidelines:
- If you capture your candidate architectures and architectural test cases in a document, keep the document lightweight so that you can easily update it. Such a document may include details of your objectives, application type, deployment topology, key scenarios and requirements, technologies, quality attributes, and tests.
Use the quality attributes to help shape your design and implementation. For example, developers should be aware of anti-patterns related to the identified architectural risks, and use the appropriate proven patterns to help address the issues.
Communicate the information you capture to relevant team members and other stakeholders. This may include your application development team, your test team, and your network and system administrators.
Reviewing Your Architecture¶
Reviewing the architecture for your application is a critically important task in order to reduce the cost of mistakes and to find and fix architectural problems as early as possible. Architecture review is a proven, cost-effective way of reducing project costs and the chances of project failure. Review your architecture frequently: at major project milestones, and in response to other significant architectural changes. Build your architecture with common review questions in mind, both to improve your architecture and to reduce the time required for each review.
The main goal of an architecture review is to determine the feasibility of your baseline and candidate architectures, and verify that the architecture correctly links the functional requirements and the quality attributes with the proposed technical solution. Additionally, it helps you to identify issues and recognize areas for improvement.
Scenario-Based Evaluations
Scenario-based evaluations are a powerful method for reviewing an architecture design. In a scenario-based evaluation, the focus is on the scenarios that are most important from the business perspective, and which have the greatest impact on the architecture. Consider using one of the following common review methodologies:
- Software Architecture Analysis Method (SAAM). SAAM was originally designed for assessing modifiability, but later was extended for reviewing architecture with respect to quality attributes such as modifiability, portability, extensibility, integratability, and functional coverage.
- Architecture Tradeoff Analysis Method (ATAM). ATAM is a refined and improved version of SAAM that helps you review architectural decisions with respect to the quality attributes requirements, and how well they satisfy particular quality goals.
- Active Design Review (ADR). ADR is best suited for incomplete or in-progress architectures. The main difference is that the review is more focused on a set of issues or individual sections of the architecture at a time, rather than performing a general review.
- Active Reviews of Intermediate Designs (ARID). ARID combines the ADR aspect of reviewing in-progress architecture with a focus on a set of issues, and the ATAM and SAAM approach of scenario-based review focused on quality attributes.
- Cost Benefit Analysis Method (CBAM). This CBAM focuses on analyzing the costs, benefits, and schedule implications of architectural decisions.
- Architecture Level Modifiability Analysis (ALMA). ALMA evaluates the modifiability of architecture for business information systems (BIS).
- Family Architecture Assessment Method (FAAM). FAAM evaluates information system family architectures for interoperability and extensibility.
For information about techniques for analyzing and reviewing architecture designs, see "Evaluating Software Architectures: Methods and Case Studies (SEI Series in Software Engineering)" by Paul Clements, Rick Kazman, and Mark Klein (Addison-Wesley Professional , ISBN-10: 020170482X, ISBN-13: 978-0201704822)
Representing and Communicating Your Architecture Design¶
Communicating your design is critical for architecture reviews, as well as to ensure it is implemented correctly. You must communicate your architectural design to all the stakeholders including the development team, system administrators and operators, business owners, and other interested parties.
One way to think of an architectural view is as a map of the important decisions. The map is not the terrain; instead, it is an abstraction that helps you to share and communicate the architecture. There are several well-known methods for describing architecture to others, including the following:
- 4+1. This approach uses five views of the complete architecture. Four of the views describe the architecture from different approaches: the logical view (such as the object model), the process view (such as concurrency and synchronization aspects), the physical view (the map of the software layers and functions onto the distributed hardware infrastructure), and the development view. A fifth view shows the scenarios and use cases for the software. For more information, see "Architectural Blueprints—The “4+1” View Model of Software Architecture" at http://www.cs.ubc.ca/~gregor/teaching/papers/4+1view-architecture.pdf.
- Agile Modeling. This approach follows the concept that content is more important than representation. This ensures that the models created are simple and easy to understand, sufficiently accurate, and consistent. The simplicity of the document ensures that there is active stakeholder participation in the modeling of the artifact. For more information, see "Agile Modeling: Effective Practices for eXtreme Programming and the Unified Process" by Scott Ambler (J. Wiley, ISBN-10: 0471202827, ISBN-13: 978-0471202820).
- IEEE 1471. IEEE 1471 is the short name for a standard formally known as ANSI/IEEE 1471-2000, which enhance the content of an architectural description; in particular giving specific meaning to context, views, and viewpoints. For more information, see “Recommended Practice for Architecture Description of Software-Intensive Systems” at http://standards.ieee.org/reading/ieee/std_public/description/se/1471-2000_desc.html.
- Unified Modeling Language (UML). This approach represents three views of a system model. The functional requirements view (functional requirements of the system from the point of view of the user, including use cases); the static structural view (objects, attributes, relationships, and operations including class diagrams); and the dynamic behavior view (collaboration among objects and changes to the internal state of objects, including includes sequence, activity, and state diagrams). For more information, see "UML Distilled: A Brief Guide to the Standard Object Modeling Language" by Martin Fowler (Addison-Wesley Professional, ISBN-10: 0321193687, ISBN-13: 978-0321193681)