Architecture and Design Solutions at a Glance

J.D. Meier, Alex Homer, David Hill, Jason Taylor, Prashant Bansode, Lonnie Wall, Rob Boucher Jr, Akshay Bogawat

Objectives

  • Learn about the typical general approach to designing application architectures.
  • Learn about the different types of applications that you can build.
  • Learn about the key factors you must consider when designing application architectures.
  • Learn about the layered approach to application design.
  • Learn about the quality attributes that affect the overall success and acceptance of an application.

Overview

This chapter presents a wide-ranging overview of the key factors involved in designing the architecture for your applications. It describes the general steps in the process, the types of applications you can build, the typical layered architecture used for applications, and the design approaches for data access, services, and quality attributes.

General

The following guidelines will help you to understand some of the fundamental techniques to use when designing your application. Use these guidelines as a starting point toward understanding how to design your application, how to structure your application, how to use layers, and how to review your design.
  • How to design your architecture
First, determine the objectives of your architectural design, which will help you to focus on solving the right problems. Then identify the key scenarios or use cases that are most critical from your application’s perspective and that have maximum impact on the architecture. The use cases will help you to identify critical problem areas and will also help in evaluating and reviewing the architecture. To achieve the architectural objectives, identify the application type, deployment architecture, architecture style, and related technologies in view of the identified key scenarios. While doing so, ensure that you take into account any infrastructural and organizational constraints. Identify the quality attributes (performance, security, etc.) and cross-cutting concerns (exception handling, auditing and logging, and so on) that are important from an application perspective, to make sure that the architecture adheres to their requirements and objectives. Finally, define the architecture solution and review/validate it against the key scenarios you identified.

For more information, see Chapter 4 - Designing Your Architecture

  • How to choose a deployment topology
When you design your application architecture, you must take into account corporate policies and procedures, together with the infrastructure on which you plan to deploy your application. If the target environment is rigid, your application design must reflect the restrictions that exist in that rigid environment. Your application design must also take into account quality attributes such as performance, security, and maintainability. Sometimes you must make design tradeoffs because of protocol restrictions and network topologies. Identify the requirements and constraints that exist between application architecture and infrastructure architecture early in the development process. Use a layered design that separates presentation, business, and data access logic, to improve scalability and maintainability. To avoid unnecessary remote calls and additional network latency, stay in the same process where possible. If you do need a distributed architecture, consider the implications of remote communication when you design your interfaces. For example, you might need a distributed architecture because security policy prevents you from running business logic on your Web server, or you might need a distributed architecture because you need to share business logic with other applications, Try to reduce round trips and the amount of traffic that you send over the network.

For more information, see Chapter 5 - Deployment Patterns
  • How to structure your application
Start at the highest level of abstraction and begin by grouping your application functionality into logical layers. Understand the available deployment strategies for the physical structure and tiers, and identify how the logical layers will map to the physical tiers. Identify communication strategy and the protocols that can be used for communication between the layers and tiers in your application. Define interfaces for the layers, the information that will be communicated between layers, and the form of that communication.

For more information, see Chapter 3 - Architecture and Design Guidelines
  • How to decide on your layering strategy
When grouping the components in a layer, make sure that the components depend only on components in the same layer or components in a lower layer. Use loose coupling between layers. Avoid any circular dependencies between layers. Use only the layers that are required and that are relevant to your scenario. For example, if your application does not have a user interface (UI), you will not require a presentation layer, but only a programmatic (service) interface. If your application has minimal or no business logic (for example, a reporting application), you might not require a business layer. If your business logic is not shared by other applications, or is not located on a remote tier, you might not require a service layer. If your application does not use an external data source, you might not require a data access layer.

For more information, see Chapter 9 - Layers and Tiers
  • How to perform architecture and design reviews
Identify the architecture objectives and key scenarios for your applications that have the greatest impact on the application architecture. Establish design and architecture standards for your application; use these standards to perform design and architecture inspections, using a question-driven approach with respect to architecture objectives, infrastructure and organizational constraints, performance, and security goals, to focus your efforts. Use the key scenarios identified for scenario-based evaluations, such as Software Architecture Analysis Method (SAAM), Architecture Tradeoff Analysis Method (ATAM), and so on.

For more information, see Chapter 4 - Designing Your Architecture

Application Types

The following guidelines will help you to understand the fundamental factors you must consider when choosing an application type. Use these guidelines as a starting point toward understanding how to choose an application type, and the key differences between each application type covered in this guide. For example, device resources and performance are key considerations when designing a mobile application; choice of UI design patterns is a key consideration when designing a rich client application; and changes to your UI design and deployment paradigms are key considerations when designing a rich Internet application. Key considerations when designing a service interface include choosing a pattern for effective decoupling. Key considerations when designing a Web application include layering, as well as the amount of client-side processing to use.
  • How to choose an application type
Your choice of application type will be driven primarily by the scenarios that you want to support. If you want to leverage client resources and support disconnected scenarios, consider a rich client application. If you want to provide the application UI over the Web, consider building a Web application. If you want to support advanced graphics and streaming media in a Web-deployed scenario, consider a rich Internet application (RIA). If you want to expose a loosely coupled interface to remove clients without a UI, consider building a service. If you want to support mobile devices over the Internet, consider designing a mobile Web application. If you want to support mobile devices in which you leverage device resources or need to support partially disconnected scenarios, consider a mobile rich-client application.

For more information, see Chapter 14 - Application Archetypes
  • How to design a Web application
Most of the code associated with a Web application resides on a Web server, with some code implemented in the client browser. The design you use on the Web server can vary, based on the type and size of the application you are building. For smaller applications with few or no business rules, a client/server design can be used where presentation code that generates HTML interacts directly with data-access components. For most business applications, or larger applications that contain business rules, consider using a layered design that separates presentation, business, and data-access functionality into separate layers. In addition, the interaction between the presentation and business layers should be message-based, which is better suited to the stateless nature of Web application requests. On the client, you can improve the user experience by using dynamic HTML (DHTML), JavaScript, Asynchronous JavaScript and XML (AJAX), or a combination of all three technologies. For example, with AJAX you can implement lazy loading and partial updates to page content, which will improve performance and prevent the “reload flash” when a user interacts with the page.

For more information, see Chapter 15 - Web Applications
  • How to design a rich client application
For reusability and testability, separate the presentation logic from the UI implementation by using a design patterns such as Model-View-Controller (MVC). Design to provide a suitable and usable interface in terms of layout, navigation, choice of controls, and localization. Extract business rules and other tasks not related to the UI into a separate business layer. Use a message-based interface to communicate with services deployed on separate physical tiers. Avoid tight coupling to objects in other layers by using common interface definitions, abstract base classes, or message-based communication. For example, implementing the Dependency Injection and Inversion of Control patterns can provide a shared abstraction between layers.

For more information, see Chapter 17 - Rich Client Applications
  • How to design a rich Internet application (RIA)
Plan to use a Web-based infrastructure, because RIA implementations require an infrastructure similar to that of Web applications. Design your application to run in the browser sandbox. When designing an RIA, consider using a single page that changes dynamically as the user works with the application. Multi-page designs are more complex in an RIA, and require additional considerations such as deep linking and UI screen navigation. Design for usability, such as the ability to pause and navigate to the appropriate point in a workflow without restarting the whole process. RIA implementations have a small footprint on the client, but require a browser plug-in. Design for scenarios in which the browser plug-in is not already installed, including non-interruptive plug-in installation and displaying informative error messages if an installation problem should occur.

For more information, see Chapter 16 - Rich Internet Applications (RIA)
  • How to design a service
When designing a service, there are general guidelines that should be followed; for example, design for extensibility, use coarse-grained interfaces, never assume how the client will use the service, and decouple the interface from the implementation. The best way to support these guidelines is to introduce a service layer in your design that sits between consumers of the service and the business layer that supports the service. Within the service layer, you define interface contracts, classes to translate between the interface and the business layer, and concrete classes that implement the interface. In most cases, interaction with the business layer is accomplished by using a Façade pattern, which allows you to combine multiple business operations into a single application-scoped service operation.

For more information, see Chapter 18 - Services
  • How to design a mobile application
Design specifically for the device instead of trying to reuse the architecture or UI from a desktop application or a Web application. When choosing which device types to support, consider screen size and format, CPU performance characteristics, memory and storage space, development tool and environment support, as well as user requirements and organizational constraints. Design your caching, state management, and data-access mechanisms with intermittent network connectivity in mind.

For more information, see Chapter 19 - Mobile Applications

Architecture Frame

The following guidelines will help you to understand the fundamental cross-cutting factors you must consider when designing your chosen application type. Use these guidelines as a starting point toward understanding how to think about key functionality that cuts across layers and tiers. For example, your exception-management strategy should be designed to be consistent across your entire application, and not with just a single layer in mind.
  • How to design your exception-management strategy
Use structured exception handling to build robust code. Use exceptions instead of error codes where possible. Do not reveal internal system or application details, such as stack traces, SQL statement fragments, and so on. Ensure that this type of information is not allowed to propagate to the end user, or beyond your current trust boundary. Fail securely in the event of an exception, and make sure that your application denies access and is not left in an insecure state. Use finally blocks to guarantee that resources are cleaned up when exceptions occur; for example, close your database connections in a finally block. Do not log sensitive or private data such as passwords, which could be compromised. When the exception contains user input in the exception message, ensure that you sanitize and validate it; for example, if you return an HTML error message, you should encode the output to avoid script injection.

For more information, see Chapter 3 - Architecture and Design Guidelines
  • How to instrument your application
Instrumentation is used when you have a specific problem and you need additional information in order to solve that problem. This could be a debugging issue, a performance issue, a security issue, a manageability issue, and so on. This is different than logging in that logging is a general approach to pushing information into log files that might need to be audited in the future, versus a targeted approach to get information for a specific problem. Options for instrumentation include event tracing for Microsoft® Windows®, trace and debug classes, custom performance counters, and Windows Management Instrumentation (WMI). For logging, consider the Logging Application Block in the Enterprise Library.

For more information, see Chapter 3 - Architecture and Design Guidelines
  • How to design for transactions
Use connection-based transactions when accessing a single data source. Where you cannot use transactions, implement compensating methods to revert the data store to its previous state. Avoid holding locks for long periods; for example, when using long-running atomic transactions. Consider using compensating locks for long-running transactions. If the chance of a data conflict from concurrent users is low (for example, when users are generally adding data or editing different rows), consider using optimistic locking during data access. If the chance of a data conflict from concurrent users is high (for example, when users are likely to be editing the same rows), consider using pessimistic locking during data access. If transactions take a long time to complete, consider using asynchronous transactions that call back to the client when complete. You can perform transactions using T-SQL commands, ADO.NET, or System.Transaction. T-SQL transactions are most efficient for server-controlled transactions on a single data store. Keep transactions as short as possible, consider your isolation level, and keep read operations to a minimum inside a transaction.

For more information, see Chapter 3 - Architecture and Design Guidelines

Presentation Layer

The following guidelines will help you to understand the fundamental factors you must consider when designing the presentation layer for your application. Use these guidelines as a starting point toward understanding key concerns, such as how to validate input on the client and on the server, and how to choose between the Model-View-Controller (MVC) and Model-View-Presenter (MVP) patterns.
  • How to validate input
Assume that all input data is malicious. Constrain, reject, and sanitize your input because it is easier to validate data for known valid types, patterns, and ranges than it is to validate data by looking for known bad characters. Validate data for type, length, format, and range. Consider using regular expressions for validating the inputs. For an improved user experience, consider using client-side validation, but always perform validation at the server as well. Encode your output.

For more information, see Chapter 3 - Architecture and Design Guidelines
  • How to use the MVC pattern
To use the Model-View-Controller (MVC) pattern effectively, you must understand the division of labor within the MVC triad (the Model, the View, and the Controller). You must also understand how the three parts of the triad communicate with each other to process requests from user input. The Model represents data, and the View is the UI, which displays the data to the user and contains controls for the user to interact with the data and the application. The Controller is responsible for handling requests, initializing the Model and choosing the appropriate View. Common Web implementations use HTTP handlers or Internet Server API (ISAPI) filters to intercept requests and send them directly to a controller. There are two main variations of the MVC pattern: the Passive Model and the Active Model. In the Passive Model pattern, changes to the Model are only captured when the Controller processes a request. However, in the Active Model pattern, an Observer pattern implementation can be used to notify the View and/or the Controller when changes occur in the Model. One of the limitations with this pattern is that, because the controller is responsible for intercepting and handling requests, you lose capabilities associated with the View such as the ability to handle control events and the use of viewstate in ASP.NET.

For more information, see Chapter 10 - Presentation Layer Guidelines
  • How to use the MVP pattern
The Model-View-Presenter (MVP) pattern is very similar to the MVC pattern, with the main difference being that Views handle requests and pass them to a presenter, which provides controller logic. Similar to the controller in MVC, the Presenter is responsible for processing requests and initializing the model. The main advantage of using this pattern over MVC is that, because the view handles requests, you also have support for control events and the ability to maintain the state of controls in the view. There are two main variations on this pattern, Passive View and Supervising Controller. With Passive View, requests are intercepted by the View and passed to the Presenter, and then the Presenter initializes fields in the View through an interface. This variation completely decouples the view from the Model and provides the highest level of testability. With Supervising Controller, the View passes requests to the Presenter, the Presenter notifies the View when the Model is initialized, and the View accesses the Model directly. This variation is useful when you have a lot of data that needs to be presented in the View, which makes Passive View impractical.

For more information, see Chapter 10 - Presentation Layer Guidelines

Business Layer

The following guidelines will help you to understand fundamental factors you must consider when designing the business layer for your application. Use these guidelines as a starting point toward understanding key concerns, such as when to use business entities, how to implement business components, and how to expose your business layer as a service.
  • How to implement business entities
If you are designing a small Web application or a service, and you want to take advantage of the disconnected behavior they provide, consider using DataSets. If you are working with content-based applications that have few or no business rules, consider using XML. If you have complex business rules related to the business domain, or if you are designing a rich client where the domain model can be initialized and held in memory, consider using custom Domain Model objects. If your tables or views in the database represent the business entities used by your application, consider using custom objects. If the data you are consuming is already in XML format, or if you are working with read-only document-based data, consider using custom XML objects.

For more information, see Chapter 11 - Business Layer Guidelines
  • How to implement business components
The type of business component you implement depends on your business rules. If you have volatile business rules, consider storing them in a separate rules engine. If you want your business rules to be separate from the business data, consider using business process components. If your business processes involve multiple steps with long-running transactions, consider using business workflow components. A well-designed business component exposes data and functionality based on how the data is used, and abstracts the underlying data store and service. Do not mix unrelated functionality within a business component; for example, do not mix data access logic and business logic within the same component. Consider designing consistent input and output data formats for business components.

For more information, see Chapter 11 - Business Layer Guidelines
  • How to design application service façades
A well-designed application service façade exposes a simple interface by encapsulating cohesive behavior that is specific to a set of related business operations. Avoid including business logic in a service interface in order to improve reusability and maintainability and reduce duplication of code. Consider using standard protocols such as the SOAP as the communication medium to ensure maximum compatibility with a range of clients.

For more information, see Chapter 11 - Business Layer Guidelines

Data Access

The following guidelines will help you to understand the fundamental factors you need to consider when designing the data layer for your application. Use these guidelines as a starting point toward understanding the key concerns, such as how to design your data access layer, how to manage connections, the differences between stored procedures and dynamic SQL, how to think about data access performance, and how to effectively pass data through your application’s layers and tiers.
  • How to design your data access layer
If you choose to access tables directly from your application without an intermediate data access layer, you may improve the performance of your application at the expense of maintainability. The data access logic layer provides a level of abstraction from the underlying data store. A well-designed data access layer exposes data and functionality based on how the data is used, and abstracts the underlying data store complexity. Do not arbitrarily map objects to tables and columns, and avoid deep object hierarchies. For example, if you want to display a subset of data, and your design retrieves an entire object graph instead of the necessary portions, there is unnecessary object creation overhead. Evaluate the data you need and how you want to use the data against your underlying data store.

For more information, see Chapter 12 - Data Access Layer Guidelines
  • How to design your connection-management approach
Pool connections. Connections are an expensive and scarce resource, which should be shared between callers by using connection pooling. Opening a connection for each caller limits scalability. Connect by using service accounts associated with a trusted subsystem security model. Open database connections only when you need them. Close the database connections as soon as you are finished—do not open them early, and do not hold them open across calls.

For more information, see Chapter 12 - Data Access Layer Guidelines
  • How to choose between stored procedures and dynamic SQL
When choosing between stored procedure and dynamic SQL, you need to consider the abstraction requirements, maintainability, and any environment constraints. Consider whether you need to implement abstraction in the database in the form of stored procedures or in the data layer in the form of dynamic SQL data access patterns or object/relational mapping (O/RM). If you have a small application with limited business rules, consider using dynamic SQL as it is the simplest model with the least development overhead. If you are building a larger application with maintainability requirements, consider using stored procedures since most changes to the database schema will have a minimal impact on application code. For security considerations, you should always use typed parameters, either passed to a stored procedure or used when creating dynamic SQL.

For an in-depth discussion on how to make an informed choice, see Chapter 12 - Data Access Layer Guidelines
  • How to improve data access performance
Minimize processing on the server and at the client. Minimize the amount of data passed over the network. Use database connection pooling to share connections across requests. Keep transactions as short as possible to minimize lock durations and to improve concurrency. However, do not make transactions so short that access to the database becomes too chatty.

For more information, see Chapter 12 - Data Access Layer Guidelines
  • How to pass data across layers and tiers
Consider scalar values when the consumer is interested only in the data and not the type or structure of the entity. Do not consider scalar values if your design is not capable of handing schema changes. Consider XML strings when you must support a variety of callers, including third-party clients. Consider custom objects when you must handle complex data, communicate with components that know about the object type, or require better performance through binary serialization. Consider using Data Transfer Objects (DTOs) that combine multiple data structures into a single structure in order to reduce round trips between layers and tiers. With the Microsoft .NET Framework, do not pass DataReader objects between layers because they require an open connection. Consider using DataSets for disconnected scenarios in simple CRUD (Create, Read, Update, Delete)-based applications. A DataSet contains schema information and maintains a change record, which means it can be modified and used to update the database without requiring additional code. However, it is important to understand that DataSets are expensive to create and serialize compared to custom objects.

For more information, see Chapter 12 - Data Access Layer Guidelines

Services

The following guidelines will help you to understand the fundamental factors you need to consider when designing the service layer for your application. Use these guidelines as a starting point toward understanding the key concerns, such as when to use business entities, how to design your service interface, how to choose a Web service technology, and how to think about Representational State Transfer (REST) and SOAP.
  • How to design a service
When designing services, you must consider the availability and stability of the service, and ensure that it is configurable and can be aggregated so that it can accommodate changes to the business requirements. In most cases, you want to design services that are autonomous, provide explicit boundaries, do not expose internal classes, and use policy to define interaction requirements. You should also design for idempotency so that the service can manage messages that arrive more than once; design for commutativity so that the service can handle messages that arrive in the wrong order; and design for invalid requests by validating them against a schema or known format. Consider using standard elements to compose the complex types used by your service.

For more information, see Chapter 13 - Service Layer Guidelines
  • How to expose your application as a service
The approach you take to exposing an application as a service depends on where you are in the development life cycle of the application. If you already have an application and want to expose operations as services, you should identify the necessary operations and then define interface contracts that combine operations in order to produce application-scoped procedures. The main thing you do not want to do is expose component- or object-based operations as service operations. When starting from scratch, you should first define the service interface contracts that an application needs to support. The main goal is to provide coarse-grained interface contracts that support business-process or client requirements without focusing on the implementation. Once you have defined the contracts, you can then focus on how to implement code that supports the contracts.

For more information, see Chapter 13 - Service Layer Guidelines
  • How to choose between ASP.NET Web services and WCF services for services
ASP.NET Web services are a good choice for simple HTTP-based services hosted in Internet Information Services (IIS). WCF is a good choice if you need the performance of Transmission Control Protocol (TCP) communication over HTTP, or if you need to host the service without a Web server. WCF provides support for the WS* specification, which includes support for end-to-end security and reliable communication. WCF allows you to implement duplex communication, and you can also use it with Windows Message Queuing and as a Windows service. In addition, you have more options with regard to protocols, bindings, and formats. Keep in mind that WCF requires the .NET Framework 3.0 or higher.

For more information, see Chapter 13 - Service Layer Guidelines
  • How to choose between REST and SOAP
Representational State Transfer (REST) and SOAP represent two different styles for implementing services. REST uses HTTP, which means that it works very much like a Web application, while SOAP is an XML-based messaging protocol that can be used with any communication protocol. Although both REST and SOAP can be used with most service implementations, the REST architectural style is better suited for public services or cases where a service can be accessed by unknown consumers. SOAP is better suited for implementing a loosely coupled Remote Procedure Call (RPC) interface between layers of an application. With SOAP, you are not restricted to HTTP, and it provides the underlying framework for more advanced Web Service standards, such as the ability to enlist in transactions.

For more information, see Chapter 13 - Service Layer Guidelines

Quality Attributes

The following guidelines will help you to understand how focusing on the quality attributes can produce a more successful design. The guidelines help you to understand how to design your application, keeping security and performance in mind right from the beginning.
  • How to design for security
Use threat modeling to systematically identify threats instead of applying security in a haphazard manner. Itemize your application’s important characteristics, assets, and actors to help you identify threats. A detailed understanding of your application will also help you uncover more relevant and detailed threats. Use a security frame to focus on areas where mistakes are most often made. Key categories in a security frame include auditing and logging, authentication, authorization, configuration management, cryptography, exception management, input and data validation, and sensitive data. Rate the threats based on the risk of an attack or occurrence of a security compromise and the potential damage that could result. This allows you to deal with threats in the appropriate order.

For more information, see Chapter 7 - Quality Attributes
  • How to design for performance
Use performance modeling early in the design process to help you evaluate your design decisions against your objectives before you commit time and resources. Identify your performance objectives, your workload, and your budgets. For example, performance objectives may include maximum execution time and resource utilization such as CPU, memory, disk I/O, and network I/O. Identify your constraints, such as time and hardware budget. Use load testing and unit tests to measure performance, and identify if hardware or deployment scenarios are the cause of bottlenecks. Ensure that you test with data types and data volumes that match the actual run-time scenarios.

For more information, see Chapter 7 - Quality Attributes
  • How to identify and evaluate performance issues
Focus on the critical areas where the correct approach is essential and where mistakes are often made. Identify requirements, cost, and budget restraints, and whether improvements can come from additional hardware and infrastructure, improved application code, or by adopting a different deployment approach. Perform design inspections and code inspections to identify poor practices that could lead to bottlenecks. Organize and prioritize your performance issues by using a performance frame. Key categories in a performance frame include data structures and algorithms, communication, concurrency, resource management, coupling and cohesion, caching, and state management.

For more information, see Chapter 7 - Quality Attributes

Last edited Dec 15, 2008 at 6:50 PM by prashantbansode, version 4

Comments

No comments yet.