Protecting Patients through Background Checks

Separation of Concerns Using the Decorator Pattern

Background Check System

IT Technical Design Guide

Version 01

1/29/2015

Table of Contents

1Introduction

1.1Overview

1.2Interfaces

1.3Implementation

1.4Decorations

2Application

2.1Database Model

2.2Domain Model

2.3Interface Definition

2.4Implementation

3Demo Website

3.1ApplicationContext

3.2Base Controller

3.3Sample Controller

3.4Sample View

4Decorations

4.1Caching

4.2Logging

4.3Scalability

5Demonstration

6Other Considerations

6.1Dependencies

6.2Virtual Behavior

6.3Mock Implementations

6.4Code Generation

7Conclusion

1Introduction

The purpose of this document is to demonstrate a straightforward approach to application/service development based on using the decorator pattern to separate concerns and provide location transparency. Such an approach allows developers to focus on core functionality while deferring secondary concerns, which improves productivity and provides a testable system more quickly. Utilization of the decorator pattern allows additional functionality to be inserted without impact to existing code, including the injection of a service tier to improve scalability. In order to demonstrate this approach, a simple, sample solution will be created implementing user management.

1.1Overview

The basic approach is to define interfaces along with their associated data, develop the core implementation, and then utilize the decorator pattern to provide enhanced functionality.

1.2Interfaces

Layering is one of the best ways to hide complexity. The most significant theme of this document is the mantra “code to an interface, not an implementation.” An interface should be defined for each “service” that will be developed. This interface may correspond to the actual Windows Communication Foundation (WFC) or other web service, a data access repository, a module/component of an application, or it can encompass the entire application as an application program interface (API).

1.3Implementation

Once the interface has been defined, the primary task is to implement its most fundamental functionality.This core implementation should focus solely on the tasks required to fulfill the interface’s contract. This may require anything from querying a database, invoking a remote service, manipulating domain objects, calling functionality defined by another interface, and/or other common tasks.Once the interface is implemented, the client code needs only to instantiate and consume it through its contract (not directly via the implementation).

1.4Decorations

With the primary functionality provided by the core implementation of the interface, it should be possible to complete most simple applications. However, this document will demonstrate how to add caching (to improve performance), logging (for auditing or diagnostics), and scalability (by injecting an application/service tier).These, and other such decorations, will not require significant modifications to the client application’s code, but can provide a tremendous amount of background functionality.

2Application

In order to demonstrate the concepts described above, a simplistic user management interface will be developed. A Microsoft SQL Server database will be created to define and store our user information.Microsoft Enterprise Library will be used as our data access layer. Class libraries will be created for the interface and each of the various implementations. Finally, the base ASP.NET MVC web application will be modified to consume the interface, providing a better client example than just unit tests would.

2.1Database Model

The image below depicts the database model for user management. It consists of tables representing Users, Roles and their many-to-many relationship via UserRoles.

2.2Domain Model

It is not uncommon for larger projects to have a rich domain model that serves as the core implementation of the system. The complexity that a domain model brings is the need to develop additional interfaces and their corresponding entities that reside on both sides of the domain layer. The benefits of a rich domain model include the ability to exploit all of the power of the Microsoft .NET Framework and object-oriented design/developmentwith independence from external concerns.

Although the demo application will not contain such a domain model, it’s important to note that most of the concepts presented in this document are still applicable. A set of repository interfaces and their associated database entities could be developed to provide persistence into and queries out of the database. Additionally, the original service/application layer could provide its own interface and entities above the domain layer. This approach provides additional decoupling of the various layers from one another, but at the cost of additional development and data translation efforts.

Without an explicit domain model, the core implementation of the application/service interface will be responsible for implementing both the business logic and interaction with the data access layer. Since we will be utilizing the Microsoft Enterprise Framework for data access, the case could be made that a domain model does exist but isn’t being fully exploited.

2.3Interface Definition

The interface is the contract definition consisting of methods and any related objects. A class library will be created to contain this interface and dependent data transfer objects, as shown in the image below.

2.3.1Data Transfer Objects

Data transfer objects (DTOs) are typically plain-old-CLR-objects (POCOs) that have very limited functionality. Using DTOs instead of domain objects provides a layer of abstraction that allows their underlying counterparts to change without breaking existing contracts. However, the use of DTOs can require additional development to design and translate to/from their native models, but tend to be worth the effort when utilized properly.

On one extreme, DTOs can represent very specific needs of the application. For example, a web/WFC service may utilize specific DTOs for every method’s request and response. This leads to a very coarse-grained service layer, but the number of DTOs becomes difficult to manage as the number of service methods increases.

On the other extreme, DTOs could directly represent their corresponding database/domain entities.Repository interfaces would follow such an approach. However, this approach can lead to a very “chatty” service layer where multiple methods must be invoked to get the data required (along with data that was not required, but came automatically with the DTO). Fortunately, this approach is the most straight-forward and tends to lend itself extremely well to code generation.

The best approach for most applications lies somewhere in-between these two extremes. Ultimately, the goal is to achieve as much reuse from the DTOs as possible without excessive compromise or complication.

The demo application will utilize an approach closer to the latter, as there will be User and Role DTOs that correspond directly to their database counterparts. The images below depict the DTOscorresponding to theUser and User Roletables in the database. The UserBase and RoleBase classes are defined to demonstrate some flexibility of DTOs. The idea is that these base classes can be used to populate pick lists in a user interface where the full entities are not desired. Alternatively, a UserProfile class could be created that inherited from User and also contained a set of the user’s roles. The possibility for DTOs is endless, but must focus only on the representation of the data since it will be the role of the interface to define any associated behavior.

2.3.2Interface

The design of the interface and DTOs is typically performed iteratively. The interface is responsible for defining the application/service contract which relies heavily on the associated DTOs. The image below shows the start to a sample interface definition utilizing the DTOs already defined.

When defining interface methods, it is usually a good idea to avoid method overloading because certain technologies (such as web services and stored procedures) do not support overloading and require aliasing and workarounds, which can cause a slight decrease in maintainability and opportunities to generate code.

Also, we recommend using an Object-Action-Details naming convention, such as “UserGetByUsername” instead of “GetUserByUsername” or the overloaded “GetUser.”This will organize methods alphabetically by object when viewed in IntelliSense, the MSVS Members dropdown, SQL Server’s list of stored procedures, and other applicable places. You will not have to search through hundreds of “Gets” to find the method desired.

2.4Implementation

This section describes a typical implementation of the type of interface recommended above. Separate class libraries are created for each implementation layer.

2.4.1Data Access Layer

A class library is created in order to implement the data access layer. The core interface implementation will utilize this to fulfill its contract. If there was a domain model, it would utilize the data access layer and the core implementation would utilize the domain model instead.

The demo application is utilizing Microsoft Enterprise Library, so the class library simply contains an ADO.NET Entity data model as shown in the image below.

The contents of the entity model contain entities directly mapped to our database tables, as shown in the image below.

2.4.2Core Implementation

The class library containing the core implementation contains references to Ia.Demo and Ia.Demo.Dal for the interface and data access layer, respectively. The DemoImpl class implements the IDemo interface, as shown in the image below.

The image below shows an example of the implementation of one of the IDemo methods utilizing the Enterprise Library that was created in and exposed by the Ia.Demo.Dal.

3Demo Website

With the interface defined and implemented, it is ready for consumption by a client application. An ASP.NET MVC web application will be created to demonstrate. The trick is to avoid having the application directly instantiate and consume the implementation, but utilize the interface instead. This will allow the actual implementation to be changed without impact to the client code. Although a factory class would fulfill this need, a class responsible for instantiating the implementation and exposing it via interface properties will be created instead.

The image below shows the basics of the Demo Website project. Notice that it directly references only the Ia.Demo and Ia.Demo.Impl, but not the Ia.Demo.Dallibrary. Providing direct access to the data access layer would result in direct development against it.

3.1ApplicationContext

The image below shows the implementation of the ApplicationContext class. This class can be instantiated with a particular interface implementation, but will actually instantiate its own if one is not provided. Such a class typically manages several interfaces and their instantiation, rather than just the single one in our example.

In many applications, this ApplicationContext class could be replaced with a simple static class or singleton. However, in order to maintain the testability provided by the ASP.NET MVC framework, a Base Controller class will be created to manage this ApplicationContext class and make it available to its derived controllers.

3.2Base Controller

The image below shows the Base Controller class created to manage the ApplicationContext. Notice that it also allows an explicit ApplicationContext instance to be passed in the constructor, but provides a default instantiation if one is not provided. This is a recommended approach to allow MVC Controllers to be easily tested using specific and perhaps mock implementations.

3.3Sample Controller

The image below shows a sample controller that has been modified to inherit the Base Controller containing the ApplicationContext. Notice that it uses the IDemo interface to get a list of all the User and Role DTOs and populates a view model with the results.

Note how simple and straightforward the calls to the interface are from client code. There are no complicated rituals involved, just simple method invocations. Providing a clean API to client applications should always be a goal, since the underlying implementation can always hide the messier code.

3.4Sample View

The image below shows some of the results of our efforts. The Home view shows a list of all the Users and Roles, existing Users can log on, and new Users can register.

4Decorations

This is where one might ask, “Why not just skip all of the hassle of the interface, implementation, application context, and base controllers and just slap the Entity Framework model right into the Models folder and be done with it?”Ultimately, such an approachwould cause difficultieswhen an application grows in size and complexity.With the approach described in this document, the groundwork has been laid to begin enhancing our implementation with practically no impact to the existing code base beyond adding some references and updating the ApplicationContextclass.

The remainder of this document will demonstrate how to implement caching, logging, and even scalability via the introduction of a web/WCF service. (Imagine the refactoring and regression testing effort required to move all that functionality directly out of a web application and into a service layer.)

The core implementation could be enhanced by adding more functionality into the existing implementation class. However, that would ultimately lead to a messy code base as it lacks any separation of concerns. As enhancements are added, more external dependencies are likely to make it into the implementation class library. Additionally, unit testing is hindered by the inability to test any core functionality in isolation from all of the enhancements.

The next approach that might come to mind would be to add enhancements via sub-classing and polymorphism. It is possible to mark the core implementation class’s methods as virtual and override them in the derived class. The derived class could then implement its concern and ultimately call its base class to do “the real work.” This approach is reasonable and adequate for some types of enhancements, but is not as flexible as may sometimes be needed and creates compile-time dependencies between base and derived classes that are difficult to modify.

Instead, we will use the decorator pattern to layer additional functionality on top of our core implementation. To add enhancements, such as caching, another implementation of the interface needs to be developed. However, this new implementation will require a reference to another implementation that actually does “the real work.” This reference will be via interface rather than via explicit implementation in order to keep the actual implementation classes as loosely coupled as possible.

Utilizing the decorator pattern will provide much more flexibility with much less coupling than an inheritance-based approach could provide. The downside to this approach is the burden of implementing explicit calls to the base implementation, whereas simply not overriding such methods would have the same effect using inheritance.

4.1Caching

A common enhancement to any particular interface may often be the addition of a caching layer. In this example, the Microsoft Enterprise Library’s caching will be used to provide cache management. Another optionwould be to use the System.Web.Caching.Cache, but this has a strict dependency that limits its use outside of web-based clients. A static hashtable could also be used, but lacks the sophistication that an actual cache management library provides.

The image below shows the implementation of the IDemointerface providing caching. This example assumes that the set of Roles will never change, so they are cached indefinitely upon first access.

Once the caching implementation is completed, a reference is added, and a simple change is made to the IDemo instantiation as shown in the image below. The application now benefits from the increased performance caching provides and no other modifications to the application code are necessary.

4.2Logging

Implementing a logging layer is similar to the process of implementing a caching layer. Simply choose a logging mechanism, create a class library, and implement the interface. The sample code in the image below contains comments only where logging calls may occur. Logging calls may be oriented towards detailed auditing, exception logging, or even be more diagnostic in nature (such as timing how long each call takes to execute).

The image below shows three examples of how the logging implementation can be instantiated. Notice how the decorator pattern allows these implementations to be stacked with logging calling caching calling the core implementation.

Typically, logging will be the outermost instantiatedimplementation to make sure it gets called regardless of any existing caching. However, it could also exist behind the caching layer (as shown in the third example below) if its goal was to measure performance related to cache hits and misses.

4.3Scalability

Adding enhancements such as caching and logging are decent examples of using the decorator pattern to enhance an interface with additional functionality while maintaining separation of concerns and not impacting existing code. However, the ability to inject a service layer into the application architecture is one of the most compelling reasons to follow this approach.

4.3.1WCF Service

In order to implement a WCF service layer for a particular interface, two class libraries are required: one to implement the service and another for the client. Fortunately, both are trivial and require very little time or effort.

The first step is to add attributes to the interface and corresponding DTOs, as shown in the images below.