Architecture Frame

From Guidance Share

(Difference between revisions)
Jump to: navigation, search
Revision as of 16:13, 26 March 2010 (edit)
Webmaster (Talk | contribs)

← Previous diff
Revision as of 16:13, 26 March 2010 (edit)
Webmaster (Talk | contribs)

Next diff →
Line 249: Line 249:
* If supported, use designers and metadata instead of code to define the workflow. * If supported, use designers and metadata instead of code to define the workflow.
* With human workflow, consider the nondeterministic nature of users. In other words, you cannot determine when a task will be completed, or if it will be completed correctly. * With human workflow, consider the nondeterministic nature of users. In other words, you cannot determine when a task will be completed, or if it will be completed correctly.
 +
 +
 +__NOTOC__ __NOEDITSECTION__

Revision as of 16:13, 26 March 2010

The following table lists the key areas to consider as you develop your architecture. Refer to the key issues in the table to understand where mistakes are most often made. The sections following this table provide guidelines for each of these areas.


Table 1 Architecture Frame

Area Key issues
Authentication and Authorization
  • Lack of authentication across trust boundaries
  • Lack of authorization across trust boundaries
  • Granular or improper authorization
Caching
  • Caching data that is volatile
  • Caching sensitive data
  • Incorrect choice of caching store
Communication
  • Incorrect choice of transport protocol
  • Chatty communication across physical and process boundaries
  • Failure to protect sensitive data
Composition
  • Cooperating application modules coupled by dependencies making development, testing, and maintenance more difficult
  • Dependency changes between modules, forcing code recompilation and module redeployment
  • Difficulties in dynamic UI layout and update due to hard-coded dependencies
  • Difficulty in dynamic module loading due to hard-coded dependencies
Concurrency and Transactions
  • Not protecting concurrent access to static data
  • Deadlocks caused by improper locking
  • Not choosing the correct data concurrency model
  • Long-running transactions that hold locks on data
  • Using exclusive locks when not required
Configuration Management
  • Lack of or incorrect configuration information
  • Not securing sensitive configuration information
  • Unrestricted access to configuration information
Coupling and Cohesion * Incorrect grouping of functionality
  • No clear separation of concerns
  • Tight coupling across layers
Data Access
  • Per-user authentication and authorization when not required
  • Chatty calls to the database
  • Business logic mixed with data access code
Exception Management
  • Failing to an unstable state
  • Revealing sensitive information to the end user
  • Using exceptions to control application flow
  • Not logging sufficient details about the exception
Layering
  • Incorrect grouping of components within a layer
  • Not following layering and dependency rules
  • Not considering the physical distribution of layers
Logging and Instrumentation
  • Lack of logging and instrumentation
  • Logging and instrumentation that is too fine-grained
  • Not making logging and instrumentation an option that is configurable at run time
  • Not suppressing and handling logging failures
  • Not logging business-critical functionality
State Management
  • Using an incorrect state store
  • Not considering serialization requirements
  • Not persisting state when required
Structure
  • Choosing the incorrect structure for your scenario
  • Creating an overly complex structure when not required
  • Not considering deployment scenarios
User Experience
  • Not following published guidelines
  • Not considering accessibility
  • Creating overloaded interfaces with unrelated functionality
Validation
  • Lack of validation across trust boundaries
  • Failure to validate for range, type, format, and length
  • Not reusing validation logic
Workflow
  • Not considering management requirements
  • Choosing an incorrect workflow pattern
  • Not considering exception states and how to handle them

Authentication

Designing a good authentication strategy is important for the security and reliability of your application. Failure to design and implement a good authentication strategy can leave your application vulnerable to spoofing attacks, dictionary attacks, session hijacking, and other types of attacks.

Consider the following guidelines when designing an authentication strategy:

  • Identify your trust boundaries and authenticate users and calls across the trust boundaries. Consider that calls might need to be authenticated from the client as well as from the server (mutual authentication).
  • If you have multiple systems within the application that use different user repositories, consider a single sign-on strategy.
  • Do not store passwords in a database or data store as plain text. Instead, store a hash of the password.
  • Enforce the use of strong passwords or password phrases.
  • Do not transmit passwords over the wire in plain text.

Authorization

Designing a good authorization strategy is important for the security and reliability of your application. Failure to design and implement a good authorization strategy can make your application vulnerable to information disclosure, data tampering, and elevation of privileges.

Consider the following guidelines when designing an authorization strategy:

  • Identify your trust boundaries and authorize users and callers across the trust boundary.
  • Protect resources by applying authorization to callers based on their identity, groups, or roles.
  • Use role-based authorization for business decisions.
  • Use resource-based authorization for system auditing.
  • Use claims-based authorization when you need to support federated authorization based on a mixture of information such as identity, role, permissions, rights, and other factors.

Caching

Caching improves the performance and responsiveness of your application. However, a poorly designed caching strategy can degrade performance and responsiveness. You should use caching to optimize reference data lookups, avoid network round trips, and avoid unnecessary and duplicate processing. To implement caching, you must decide when to load the cache data. Try to load the cache asynchronously or by using a batch process to avoid client delays.

Consider following guidelines when designing a caching strategy:

  • Do not cache volatile data.
  • Consider using ready-to-use cache data when working with an in-memory cache. For example, use a specific object instead of caching raw database data.
  • Do not cache sensitive data unless you encrypt it.
  • If your application is deployed in Web farm, avoid using local caches that need to be synchronized; instead consider using a transactional resource manager such as Microsoft® SQL Server® or a product that supports distributed caching.
  • Do not depend on data still being in your cache. It may have been removed.

Communication

Communication concerns the interaction between components across different boundary layers. The mechanism you choose depends on the deployment scenarios your application must support. When crossing physical boundaries, you should use message-based communication. When crossing logical boundaries, you should use object-based communication.

Consider the following guidelines when designing communication mechanisms:

  • To reduce round trips and improve communication performance, design chunky interfaces that communicate less often but with more information in each communication.
  • Use unmanaged code for communication across AppDomain boundaries.
  • Consider using message-based communication when crossing process or physical boundaries.
  • If your messages don’t need to be received in exact order and don’t have dependencies on each other, consider using asynchronous communication to unblock processing or UI threads.
  • Consider using Microsoft Message Queuing (MSMQ) to queue messages for later delivery in case of system or network interruption or failure. MSMQ can perform transacted message delivery and supports reliable once-only delivery.

Composition

Composition is the process used to define how interface components in a UI are structured to provide a consistent look and feel for the application. One of the goals of UI design is to provide a consistent interface in order to avoid confusing users as they navigate through your application. This can be accomplished by using templates, such as a master page in ASP.NET, or by implementing one of many common design patterns.

Consider the following guidelines when designing for composition:

  • Avoid using dynamic layouts because they can be difficult to load and maintain.
  • Be careful with dependencies between components. Use abstraction patterns when possible to avoid issues with maintainability.
  • Consider creating templates with placeholders. For example, use the Template View pattern to compose dynamic Web pages to ensure reuse and consistency.
  • Consider composing views from reusable modular parts. For example, use the Composite View pattern to build a view from modular, atomic component parts.

Concurrency and Transactions

When designing for concurrency and transactions related to accessing a database, it is important to identify the concurrency model you want to use and determine how transactions will be managed. For database concurrency, you can choose between an optimistic model, where the last update applied is valid, or a pessimistic model, where updates can only be applied to the latest version. Transactions can be executed within the database, or they can be executed in the business layer of an application. Where you choose to implement transactions depends on your transactional requirements. Concurrency should also be considered when accessing static data within the application or when using threads to perform asynchronous operations. Static data is not thread-safe, which means that changes made in one thread will affect other threads using the same data.

Consider the following guidelines when designing for concurrency and transactions:

  • If you have business-critical operations, consider wrapping them in transactions.
  • Use connection-based transactions when accessing a single data source.
  • Use Transaction Scope (System.Transaction) to manage transactions that span multiple data sources.
  • 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.
  • Updates to shared data should be mutually exclusive, which is accomplished by applying locks or by using thread synchronization. This will prevent two threads from attempting to update shared data at the same time.
  • Use synchronization support provided by collections when working with static or shared collections.

Configuration Management

Designing a good configuration-management mechanism is important for the security and flexibility of your application. Failure to do so can make your application vulnerable to a variety of attacks, and also leads to an administrative overhead for your application.

Consider the following guidelines when designing for configuration management:

  • Consider using least-privileged process and service accounts.
  • Categorize the configuration items into logical sections if your application has multiple tiers.
  • If your server application runs in a Web farm, decide which parts of the configuration are shares and which parts are specific to the machine on which the application is running. Then choose an appropriate configuration store for each section.
  • Encrypt sensitive information in your configuration store.
  • Restrict access to your configuration information.
  • Provide a separate administrative UI for editing configuration information.

Coupling and Cohesion

When designing components for your application, you should ensure that these components are highly cohesive, and that loose coupling is used across layers. Coupling is concerned with dependencies and functionality. When one component is dependent upon another component, it is tightly coupled to that component. Functionality can be decoupled by separating different operations into unique components. Cohesion concerns the functionality provided by a component. For example, a component that provides operations for validation, logging, and data access represents a component with very low cohesion. A component that provides operations for logging only represents high cohesion.

Consider the following guidelines when designing for coupling and cohesion:

  • Partition application functionality into logical layers.
  • Design for loose coupling between layers. Consider using abstraction to implement loose coupling between layers with interface components, common interface definitions, or shared abstraction. Shared abstraction is where concrete components depend on abstractions and not on other concrete components (the principle of dependency inversion).
  • Design for high cohesion. Components should contain only functionality that is specifically related to that component.
  • Know the benefits and overhead of loosely coupled interfaces. While loose coupling requires more code, the benefits include a shortened dependency chain and a simplified build process.

Data Access

Designing an application to use a separate data access layer is important for maintainability and extensibility. The data access layer should be responsible for managing connections with the data source and for executing commands against the data source. Depending on your business entity design, the data access layer may have a dependency on business entities; however, the data access layer should never be aware of business processes or workflow components.

Consider the following guidelines when designing data access components:

  • Avoid coupling your application model directly to the database schema. Instead, you should consider using an abstraction or mapping layer between the application model and database schema.
  • Open connections as late as possible and release them as early as possible.
  • Enforce data integrity in the database, not through data layer code.
  • Move code that makes business decisions to the business layer.
  • Avoid accessing the database directly from different layers in your application. Instead, all database interaction should be done through a data access layer.

Exception Management

Designing a good exception-management strategy is important for the security and reliability of your application. Failure to do so can make your application vulnerable to Denial of Service (DoS) attacks, and may also reveal sensitive and critical information. Raising and handling exceptions is an expensive process. It is important that the design also takes into account the performance considerations. A good approach is to design a centralized exception-management and logging mechanism, and to consider providing access points within your exception-management system to support instrumentation and centralized monitoring that assists system administrators.

Consider the following guidelines when designing an exception-management strategy:

  • Do not catch internal exceptions unless you can handle them or need to add more information.
  • Do not reveal sensitive information in exception messages and log files.
  • Design an appropriate exception propagation strategy.
  • Design a strategy for dealing with unhandled exceptions.
  • Design an appropriate logging and notification strategy for critical errors and exceptions.

Layering

The use of layers in a design allows you to separate functionality into different areas of concern. In other words, layers represent the logical grouping of components within the design. You should also define guidelines for communication between layers. For example, layer A can access layer B, but layer B cannot access layer A.

Consider the following guidelines when designing layers:

  • Layers should represent a logical grouping of components. For example, use separate layers for UI, business logic, and data access components.
  • Components within a layer should be cohesive. In other words, the business layer components should provide only operations related to application business logic.
  • When designing the interface for each layer, consider physical boundaries. If communication crosses a physical boundary to interact with the layer, use message-based operations. If communication does not cross a physical boundary, use object-based operations.
  • Consider using an Interface type to define the interface for each layer. This will allow you to create different implementations of that interface to improve testability.
  • For Web applications, implement a message-based interface between the presentation and business layers, even when the layers are not separated by a physical boundary. A message-based interface is better suited to stateless Web operations, provides a façade to the business layer, and allows you to physically decouple the business tier from the presentation tier if this is required by security policies or in response to a security audit.

Logging and Instrumentation

Designing a good logging and instrumentation strategy is important for the security and reliability of your application. Failure to do so can make your application vulnerable to repudiation threats, where users deny their actions. Log files may be required for legal proceedings to prove the wrongdoing of individuals. You should audit and log activity across the layers of your application. Using logs, you can detect suspicious activity, which can provide early indication of a serious attack. Generally, auditing is considered most authoritative if the audits are generated at the precise time of resource access, and by the same routines that access the resource. Instrumentation can be implemented by using performance counters and events to give administrators information about the state, performance, and health of an application.

Consider the following guidelines when designing a logging and instrumentation strategy:

  • Centralize your logging and instrumentation mechanism.
  • Design instrumentation within your application to detect system- and business-critical events.
  • Consider how you will access and pass auditing and logging data across application layers.
  • Create secure log file management policies. Protect log files from unauthorized viewing.
  • Do not store sensitive information in the log files.
  • Consider allowing your log sinks, or trace listeners, to be configurable so that they can be modified at run time to meet deployment environment requirements.

State Management

State management concerns the persistence of data that represents the state of a component, operation, or step in a process. State data can be persisted by using different formats and stores. The design of a state-management mechanism can affect the performance of your application. You should only persist data that is required, and you must understand the options that are available for managing state.

Consider the following guidelines when designing a state management mechanism:

  • Keep your state management as lean as possible; persist the minimum amount of data required to maintain state.
  • Make sure that your state data is serializable if it needs to be persisted or shared across process and network boundaries.
  • If you are building a Web application and performance is your primary concern, use an in-process state store such as ASP.NET session state variables.
  • If you are building a Web application and you want your state to persist through ASP.NET restarts, use the ASP.NET session state service.
  • If your application is deployed in Web farm, avoid using local state management stores that need to be synchronized. For example, consider using a remote session state service or the SQL Server state store.

Structure

Software architecture is often defined as being the structure or structures of an application. When defining these structures, the goal of a software architect is to minimize the complexity by separating items into areas of concern by using different levels of abstraction. You start by examining the highest level of abstraction while identifying different areas of concern. As the design evolves, you dive deeper into the levels, expanding the areas of concern, until all of the structures have been defined.

Consider the following guidelines when designing the application structure:

  • Identify common patterns used to represent application structure, such as client/server and N-tier.
  • Understand security requirements for the environment in which your application will be deployed. For example, many security policies require physical separation of presentation logic from business logic across different subnets.
  • Consider scalability and reliability requirements for the application.
  • Consider deployment scenarios for the application.

User Experience

Designing for an effective user experience can be critical to the success of your application. If navigation is difficult, or users are directed to unexpected pages, the user experience can be negative.

Consider the following guidelines when designing for an effective user experience:

  • Design for a consistent navigation experience. Use composite patterns for the look and feel, and controller patterns such as Model-View-Controller (MVC), Supervising Controller, and Passive View for UI processing.
  • Design the interface so that each page or section is focused on a specific task.
  • Consider breaking large pages with a lot of functionality into smaller pages.
  • Design similar components to have consistent behavior across the application. For example, a grid used to display data should implement a consistent interface for paging and sorting the data.
  • Consider using published UI guidelines. In many cases, an organization will have published guidelines to which you should adhere.

Validation

Designing an effective validation mechanism is important for the security and reliability of your application. Failure to do so can make your application vulnerable to cross-site scripting, SQL injection, buffer overflow, and other types of malicious input attacks. However, there is no standard definition that can differentiate valid input from malicious input. In addition, how your application actually uses the input influences the risks associated with exploitation of the vulnerability.

Consider the following guidelines when designing a validation mechanism:

  • Identify your trust boundaries, and validate all inputs across the trust boundaries.
  • Centralize your validation approach, if it can be reused.
  • Constrain, reject, and sanitize user input. In other words, assume that all user input is malicious.
  • Validate input data for length, format, type, and range.
  • Do not rely only on client-side validation for security checks. Instead, use client-side validation to give the user feedback and improve the user experience. Because client-side validation can be bypassed when attacking the server, use server-side validation to check for malicious input.

Workflow

Workflow components are used when an application must execute a series of information-processing tasks that are dependent on the information content. The values that affect information-processing steps can be anything from data checked against business rules to human interaction and input. When designing workflow components, it is important to consider the options that are available for management of the workflow.

Consider the following guidelines when designing a workflow component:

  • Determine management requirements. For example, if a business user needs to manage the workflow, you require a solution that provides an interface that the business user can understand.
  • Determine how exceptions will be handled.
  • Use service interfaces to interact with external workflow providers.
  • If supported, use designers and metadata instead of code to define the workflow.
  • With human workflow, consider the nondeterministic nature of users. In other words, you cannot determine when a task will be completed, or if it will be completed correctly.


Personal tools