Chapter 11: Business Layer Guidelines
J.D. Meier, Alex Homer, David Hill, Jason Taylor, Prashant Bansode, Lonnie Wall, Rob Boucher Jr, Akshay Bogawat
- Understand how the business layer fits into the overall application architecture.
- Understand the components of the business layer.
- Learn the steps for designing these components.
- Learn about the common issues faced when designing the business layer.
- Learn the key guidelines for designing the business layer.
- Learn the key patterns and technology considerations.
This chapter describes the design process for business layers, and contains key guidelines that cover the important aspects you should consider when designing business layers and business components. These guidelines are organized into categories that include designing business layers and implementing appropriate functionality such as security, caching, exception management, logging, and validation. These categories represent the key areas where mistakes occur most often in business layer design. Figure 1 shows how the business layer fits into typical application architecture. Figure 1 A typical application showing the business layer and the components it may contain
The following list explains the roles and responsibilities of the main components within the business layer:
- Application façade (optional). An application façade combines multiple business operations into a single message-based operation. You might access the application façade from the presentation layer by using different communication technologies.
- Business components. Within the business layer there are different components that provide business services, such as processing business rules and interacting with data access components. For example, you might have a business component that implements the transaction script pattern, which allows you to execute multiple operations within a single component used to manage the transaction. Another business component might be used to process requests and apply business rules.
- Business entities. Business components used to pass data between other components are considered business entities. The data can represent real-world business entities, such as products and orders, or database entities, such as tables and views. The business entities that an application uses internally can be implemented using custom objects that represent real-world or database entities your application has to work with. Alternatively, business entities can be implemented using data structures such as DataSets and Extensible Markup Language (XML) documents.
- Business workflows. Many business processes involve multiple steps that must be performed in the correct order and orchestrated. Business workflows define and coordinate long-running, multi-step business processes, and can be implemented using business process management tools.
When designing a business layer, you must also take into account the design requirements for the main constituents of the layer, such as business components, business entities, and business workflow components. This section briefly explains the main activities involved in designing each of the components and the business layer itself. Perform the following key activities in each of these areas when designing your data layer:
- Create an overall design for your business layer:
- Identify the consumers of your business layer.
- Determine how you will expose your business layer.
- Determine the security requirements for your business layer.
- Determine the validation requirements and strategy for your business layer.
- Determine the caching strategy for your business layer.
- Determine the exception-management strategy for your business layer.
- Design your business components:
- Identify business components your application will use.
- Make key decisions about location, coupling, and interactions for business components.
- Choose appropriate transaction support.
- Identify how your business rules are handled.
- Identify patterns that fit the requirements.
- Design your business entity components:
- Identify common data formats for the business entities.
- Choose the data format.
- Optionally, choose a design for your custom objects.
- Optionally, determine how you will serialize the components.
- Design your workflow components:
- Identify workflow style using scenarios.
- Choose an authoring mode.
- Determine how rules will be handled.
- Choose a workflow solution.
- Design business components to support workflow.
When designing a business layer, the goal of a software architect is to minimize the complexity by separating tasks into different areas of concern. For example, business processing, business workflow, and business entities all represent different areas of concern. Within each area, the components you design should focus on that specific area and should not include code related to other areas of concern.
Consider the following guidelines when designing the business layer:
- Decide if you need a separate business layer. It is always a good idea to use a separate business layer where possible to improve the maintainability of your application.
- Identify the responsibilities of your business layer. Use a business layer for processing complex business rules, transforming data, applying policies, and for validation.
- Do not mix different types of components in your business layer.** Use a business layer to decouple business logic from presentation and data access code, and to simplify the testing of business logic.
- Reuse common business logic.** Use a business layer to centralize common business logic functions and promote reuse.
- Identify the consumers of your business layer. This will help to determine how you expose your business layer. For example, if your business layer will be used by your presentation layer and by an external application, you may choose to expose your business layer through a service.
- Reduce round trips when accessing a remote business layer. If you are using a message-based interface, consider using coarse-grained packages for data, such as Data Transfer Objects. In addition, consider implementing a remote façade for the business layer interface.
- Avoid tight coupling between layers. Use abstraction when creating an interface for the business layer. The abstraction can be implemented using public object interfaces, common interface definitions, abstract base classes, or messaging. For Web applications, consider a message-based interface between the presentation layer and the business layer.
Business Layer Frame
There are several common issues that you must consider as your develop your design. These issues can be categorized into specific areas of the design. The following table lists the common issues for each category where mistakes are most often made.
|Category ||Common issues|
|Authentication ||Applying authentication in a business layer when not required. |
| ||Designing a custom authentication mechanism. |
| ||Failing to use single-sign-on where appropriate. |
|Authorization ||Using incorrect granularity for roles. |
| ||Using impersonation and delegation when not required. |
| ||Mixing authorization code and business processing code. |
|Business Components ||Overloading business components, by mixing unrelated functionality. |
| ||Mixing data access logic within business logic in business components. |
| ||Not considering the use of message-based interfaces to expose business components. |
|Business Entities ||Using the Domain Model when not appropriate. |
| ||Choosing incorrect data formats for your business entities. |
| ||Not considering serialization requirements. |
|Caching ||Caching volatile data. |
| ||Caching too much data in the business layer. |
| ||Failing to cache data in a ready-to-use format. |
| ||Caching sensitive data in unencrypted form. |
|Coupling and Cohesion ||Tight coupling across layers. |
| ||No clear separation of concerns within the business layer. |
| ||Failing to use a message-based interface between layers. |
|Concurrency and Transactions ||Not preventing concurrent access to static data that is not read-only. |
| ||Not choosing the correct data concurrency model. |
| ||Using long-running transactions that hold locks on data. |
|Data Access ||Accessing the database directly from the business layer. |
| ||Mixing data access logic within business logic in business components. |
|Exception Management ||Revealing sensitive information to the end user. |
| ||Using exceptions to control application flow. |
| ||Not logging sufficient detail from exceptions. |
| ||Failing to appropriately notify users with useful error messages. |
|Logging and Instrumentation ||Failing to add adequate instrumentation to business components. |
| ||Failing to log system-critical and business-critical events. |
| ||Not suppressing logging failures. |
|Service Interface ||Breaking the service interface. |
| ||Implementing business rules in the service interface. |
| ||Failing to consider interoperability requirements. |
|Validation ||Relying on validation that occurs in the presentation layer. |
| ||Failure to validate for length, range, format and type. |
| ||Not reusing the validation logic. |
|Workflows ||Not considering application management requirements. |
| ||Choosing an incorrect workflow pattern. |
| ||Not considering how to handle all exception states. |
| ||Choosing an incorrect workflow technology. |
Designing an effective authentication strategy for your business layer is important for the security and reliability of your application. Failure to do so 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:
- Only authenticate users in the business layer if it is shared by other applications. If the business layer will be used only by a presentation layer or a service layer on the same tier, avoid authentication in the business layer.
- If your business layer will be used in multiple applications, using separate user stores, consider implementing a single-sign-on mechanism.
- Only flow the caller’s identity to the business layer if you need to authenticate based on the original caller’s ID.
- If the presentation and business layers are deployed on the same machine and you need to access resources based on the original caller’s ACL permissions, consider using impersonation.
- If the presentation and business layers are deployed to separate machines and you need to access resources based on the original caller’s ACL permissions, consider using delegation. Only use delegation if it is absolutely necessary, as many environments do not allow delegation. Instead, authenticate the user at the boundary and use trusted subsystems in subsequent calls to lower layers.
- If using Web services, consider using IP Filtering to restrict web service being called only from the presentation layer.
Designing an effective authorization strategy for your business layer is important for the security and reliability of your application. Failure to do so can leave your application vulnerable to information disclosure, data tampering, and elevation of privileges.
Consider the following guidelines when designing an authorization strategy:
- Protect resources by applying authorization to callers based on their identity, account groups, or roles.
- Consider using role-based authorization for business decisions.
- Consider using resource-based authorization for system auditing.
- Consider using 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.
- Avoid using impersonation and delegation because it can significantly affect performance and scaling. It is generally more expensive to impersonate a client on a call than to make the call directly.
Business components implement business rules in diverse patterns, and accept and return simple or complex data structures. Your business components should expose functionality in a way that is agnostic to the data stores and services required to perform the work. Compose your business components in meaningful and transactionally consistent ways. Designing business components is an important task. If you fail to design business components correctly, the result is likely to be code that is impossible to maintain.
Consider the following guidelines when designing business components:
- Avoid mixing data access logic and business logic within your business components.
- Design components to be highly cohesive. In other words, you should not overload business components by adding unrelated or mixed functionality.
- If you want to keep business rules separate from business data, consider using business process components to implement your business rules.
- If your application has volatile business rules, store them in a rules engine.
- If the business process involves multiple steps and long-running transactions, consider using workflow components.
Business entities store data values and expose them through properties; they provide stateful programmatic access to the business data and related functionality. Therefore, designing or choosing appropriate business entities is vitally important for maximizing the performance and efficiency of your business layer.
Consider the following guidelines when designing business entities:
- Choose appropriate data formats for your business entities. For smaller data-driven applications consider using DataSets, and for document-centric data consider using XML for the data format. For other types of applications, consider using custom objects instead.
- Consider the analysis requirements and complexity associated with a Domain Model design before choosing to use it for business entities. A Domain Model is very good for handling complex business rules, and works best with a stateful application such as a rich client.
- If the tables in the database represent business entities, consider using the Table Module pattern.
- Consider the serialization requirements of your business entities. For example, if you are storing business entities in a central location for state management, or passing business entities across process or network boundaries, they will need to support serialization.
- Minimize the number of calls made across physical tiers. For example, use the Data Transfer Object (DTO) pattern.
Designing an appropriate caching strategy for your business layer is important for the performance and responsiveness of your application. Use caching to optimize reference data lookups, avoid network round trips, and avoid unnecessary and duplicated processing. As part of your caching strategy, you must decide when and how to load the cache data. To avoid client delays, load the cache asynchronously or by using a batch process.
Consider the following guidelines when designing a caching strategy:
- Consider caching static data that will be reused regularly within the business layer.
- Consider caching data that cannot be retrieved from the database quickly and efficiently.
- Consider caching data in a ready-to-use format within your business layer.
- Avoid caching sensitive data if possible, or design a mechanism to protect sensitive data in the cache.
- Consider how Web farm deployment will affect the design of your business layer caching solution. If a request can be handled by any server in the farm, you will need to support the synchronization of cached data that can change.
Coupling and Cohesion
When designing components for your business layer, ensure that they are highly cohesive, and implement loose coupling between layers. This helps to improve the scalability of your application.
Consider the following guidelines when designing for coupling and cohesion:
- Avoid circular dependencies. The business layer should know only about the layer below (the data access layer), and not the layer above (the presentation layer or external applications that access the business layer directly).
- Use abstraction to implement a loosely coupled interface. This can be achieved with interface components, common interface definitions, or shared abstraction where concrete components depend on abstractions and not on other concrete components (the principle of Dependency Inversion).
- Design for tight coupling within the business layer unless dynamic behavior requires loose coupling.
- Design for high cohesion. Components should contain only functionality specifically related to that component.
- Avoid mixing data access logic with business logic in your business components.
Concurrency and Transactions
When designing for concurrency and transactions, it is important to identify the appropriate concurrency model and determine how you will manage transactions. You can choose between an optimistic model and a pessimistic model for concurrency. With optimistic concurrency
, locks are not held on data and updates require code to check, usually against a timestamp, that the data has not changed since it was last retrieved. With pessimistic concurrency
, data is locked and cannot be updated by another operation until the lock is released.
Consider the following guidelines when designing for concurrency and transactions:
- Consider transaction boundaries, so that retries and composition are possible.
- Where you cannot apply a commit or rollback, or if you use a long-running transaction, implement compensating methods to revert the data store to its previous state in case an operation within the transaction fails.
- Avoid holding locks for long periods; for example, when executing long-running atomic transactions or when locking access to shared data.
- Choose an appropriate transaction isolation level, which defines how and when changes become available to other operations.
Designing an effective data-access strategy for your business layer is important for maximizing maintainability and the separation of concerns. Failing to do so can make your application difficult to manage and extend as business requirements change. An effective data-access strategy will allow your business layer to adapt to changes in the underlying data sources. It will also make it easier to reuse functionality and components in other applications.
Consider the following guidelines when designing a data-access strategy:
- Avoid mixing data-access code and business logic within your business components.
- Avoid directly accessing the database from your business layer.
- Consider using a separate data access layer for access to the database.
Designing an effective exception-management solution for your business layer is important for the security and reliability of your application. Failing to do so can leave your application vulnerable to Denial of Service (DoS) attacks, and may allow it to reveal sensitive and critical information about your application. Raising and handling exceptions is an expensive operation, so it is important that your exception management design takes into account the impact on performance.
When designing an exception-management strategy, consider following guidelines:
- Do not use exceptions to control business logic.
- Only catch internal exceptions that you can handle, or if you need to add information. For example, catch data conversion exceptions that can occur when trying to convert null values.
- Design an appropriate exception propagation strategy. For example, allow exceptions to bubble up to boundary layers where they can be logged and transformed as necessary before passing them to the next layer.
- Design an approach for catching and handling unhandled exceptions.
- Design an appropriate logging and notification strategy for critical errors and exceptions that does not reveal sensitive information.
Logging and Instrumentation
Designing a good logging and instrumentation solution for your business layer is important for the security and reliability of your application. Failing to do so can leave your application vulnerable to repudiation threats, where users deny their actions. Log files may also be required to prove wrongdoing in legal proceedings. Auditing is generally considered most authoritative if the log information is generated at the precise time of resource access, and by the same routine that accesses the resource. Instrumentation can be implemented using performance counters and events. System-monitoring tools can use this instrumentation, or other access points, to provide administrators with information about the state, performance, and health of an application.
Consider the following guidelines when designing a logging and instrumentation strategy:
- Centralize logging and instrumentation for your business layer.
- Include instrumentation for system-critical and business-critical events in your business components.
- Do not store business-sensitive information in the log files.
- Ensure that a logging failure does not affect normal business layer functionality.
- Consider auditing and logging all access to functions within business layer.
When the business layer is deployed to a separate tier, or when implementing the business layer for a service, you must consider the guidelines for service interfaces. When designing a service interface, you must consider the granularity of service operations and interoperability requirements. Generally, services should provide coarse-grained operations that reduce round trips between the service and service consumer. In addition, you should use common data formats for the interface schema that can be extended without affecting consumers of the service.
Consider the following guidelines when designing a service interface:
- Design your service interfaces in such a way that changes to the business logic do not affect the interface.
- Do not implement business rules in a service interface or in the service implementation layer.
- Design service interfaces for maximum interoperability with other platforms and services by using common protocols and data formats.
- Design the service to expose schema and contract information only, and make no assumptions on how the service will be used.
- Choose an appropriate transport protocol. For example, choose named pipes or shared memory when the service and service consumer are on the same physical machine, TCP when a service is accessed by consumers within the same network, or HTTP for services exposed over the Internet.
Designing an effective validation solution for your business layer is important for the security and reliability of your application. Failure to do so can leave your application vulnerable to cross-site scripting attacks, SQL injection attacks, buffer overflows, and other types of input attacks. There is no comprehensive definition of what constitutes a valid input or malicious input. In addition, how your application uses input influences the risk of the exploit.
Consider the following guidelines when designing a validation strategy:
- Validate all input and method parameters within the business layer, even when input validation occurs in the presentation layer.
- 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, range, format, and type.
Workflow components are used only when your application must support a series of tasks that are dependent on the information being processed. This information can be anything from data checked against business rules to human interaction. When designing workflow components, it is important to consider how you will manage the workflows, and to understand the available options.
Consider the following guidelines when designing a workflow strategy:
- Implement workflows within components that involve a multi-step or long-running process.
- Choose an appropriate workflow style depending on the application scenario.
- Handle fault conditions within workflows, and expose suitable exceptions.
- If the component must execute a specified set of steps sequentially and synchronously, consider using the pipeline pattern.
- If the process steps can be executed asynchronously in any order, consider using the event pattern.
When deploying a business layer, you must consider performance and security issues within the production environment.
Consider the following guidelines when deploying a business layer:
- Deploy the business layer to the same physical tier as the presentation or service layer in order to maximize application performance.
- If you must support a remote business layer, consider using the TCP protocol to improve application performance.
- Consider using Internet Protocol Security (IPSec) to protect data passed between physical tiers for all business layers for all applications.
- Consider using Secure Sockets Layer (SSL) encryption to protect calls from business layer components to remote Web services.
Key patterns are organized by the key categories detailed in the Business Layer Frame in the following table. Consider using these patterns when making design decisions for each category.
|Category ||Relevant patterns|
|Business Components ||Application Façade |
| ||Chain of Responsibility |
| ||Command |
|Business Entities ||Domain Model |
| ||Entity Translator |
| ||Table Module |
|Concurrency and Transactions ||Capture Transaction Details |
| ||Coarse-Grained Lock |
| ||Implicit Lock |
| ||Optimistic Offline Lock |
| ||Pessimistic Offline Lock |
| ||Transaction Script |
|Data Access ||Active Record |
| ||Data Mapper |
| ||Query Object |
| ||Repository |
| ||Row Data Gateway |
| ||Table Data Gateway |
|Workflows ||Data-driven workflow |
| ||Human workflow |
| ||Sequential workflow |
| ||State-driven workflow |
- For more information on the Domain Model, Table Module, Coarse-Grained Lock, Implicit Lock, Transaction Script, Active Record, Data Mapper, Optimistic Offline Locking, Pessimistic Offline Locking, Query Object, Repository, Row Data Gateway, and Table Data Gateway patterns, see “Patterns of Enterprise Application Architecture (P of EAA)” at http://martinfowler.com/eaaCatalog/
- For more information on the Façade, Chain of Responsibility, and Command patterns, see “data & object factory” at http://www.dofactory.com/Patterns/Patterns.aspx
- For more information on the Entity Translator pattern, see “Useful Patterns for Services” at http://msdn.microsoft.com/en-us/library/cc304800.aspx
- For more information on the Capture Transaction Details pattern, see “Data Patterns” at http://msdn.microsoft.com/en-us/library/ms998446.aspx
- For more information on the Data-Driven Workflow, Human Workflow, Sequential Workflow, and State-Driven Workflow, see “Windows Workflow Foundation Overview” at http://msdn.microsoft.com/en-us/library/ms734631.aspx and “Workflow Patterns” at http://www.workflowpatterns.com/
- Active Record. Include a data access object within a domain entity.
- Application Façade. Centralize and aggregate behavior to provide a uniform service layer.
- Capture Transaction Details.** Create database objects, such as triggers and shadow tables, to record changes to all tables belonging to the transaction.
- Chain of Responsibility. Avoid coupling the sender of a request to its receiver by allowing more than one object to handle the request.
- Coarse Grained Lock.** Lock a set of related objects with a single lock.
- Command. Encapsulate request processing in a separate command object with a common execution interface.
- Data Mapper.** Implement a mapping layer between objects and the database structure that is used to move data from one structure to another while keeping them independent.
- Data-driven Workflow.** A workflow that contains tasks whose sequence is determined by the values of data in the workflow or the system.
- Domain Model.** A set of business objects that represents the entities in a domain and the relationships between them.
- Entity Translator. An object that transforms message data types to business types for requests, and reverses the transformation for responses.
- Human Workflow.** A workflow that involves tasks performed manually by humans.
- Implicit Lock.** Use framework code to acquire locks on behalf of code that accesses shared resources.
- Optimistic Offline Lock.** Ensure that changes made by one session do not conflict with changes made by another session.
- Pessimistic Offline Lock.** Prevent conflicts by forcing a transaction to obtain a lock on data before using it.
- Query Object.** An object that represents a database query.
- Repository.** An in-memory representation of a data source that works with domain entities.
- Row Data Gateway.** An object that acts as a gateway to a single record in a data source.
- Sequential Workflow. A workflow that contains tasks that follow a sequence, where one task is initiated after completion of the preceding task.
- State-driven Workflow.** A workflow that contains tasks whose sequence is determined by the state of the system.
- Table Data Gateway.** An object that acts as a gateway to a table or view in a data source and centralizes all of the select, insert, update, and delete queries.
- Table Module. A single component that handles the business logic for all rows in a database table or view.
- Transaction Script. Organize the business logic for each transaction in a single procedure, making calls directly to the database or through a thin database wrapper.
The following guidelines will help you to choose an appropriate implementation technology and implement transaction support:
- If you require workflows that automatically support secure, reliable, transacted data exchange, a broad choice of transport and encoding options, and provide built-in persistence and activity tracking, consider using Windows Workflow (WF).
- If you require workflows that implement complex orchestrations and support reliable store and forward messaging capabilities, consider using Microsoft BizTalk® Server.
- If you must interact with non-Microsoft systems, perform electronic data interchange (EDI) operations, or implement Enterprise Service Bus (ESB) patterns, consider using the ESB Guidance for BizTalk Server.
- If your business layer is confined to a single Microsoft Office SharePoint® site and does not require access to information in other sites, consider using Microsoft Office SharePoint Server (MOSS). Note that MOSS is not suitable for multiple-site scenarios.
- If you are designing transactions that span multiple data sources, consider using a transaction scope (System.Transaction) to manage the entire transaction.