Paul Gielens:ThoughtsService

another Endpoint to my thoughts

News

Syndication

Ads


Favorites

Projects

Organizing Domain Logic

In this article we compare the Microsoft Three-Layered Services Application [Microsoft TLSA] architecture against one by Domain Driven-Design architecture [Evans DDD] for organizing domain logic. For this purpose we use the Microsoft .NET Pet Shop 4 application as an example to explain the difference between these two approaches. It then gives some comments on what Microsoft has in store to better support the latter.

This article is aimed at developers and architects who are trying to find better ways to capture the abstraction of the domain in their designs. It will help you if you have some knowledge in building enterprise applications on the .NET platform.

Recently my thinking on the Three-Layered Services Application (MS-TLSA) in comparison to Domain-Driven Design (DDD) was triggered by the following remark:

The choice between MS-TLSA and DDD is a matter of taste.

Perhaps it is. What interests me in the MS-TLSA architecture is the heart of the software: the Business Layer. This is the layer which deals with the most significant complexity in the particular domain to which the application is targeted. Let’s see what the MS-TLSA has to say about this layer.

Large enterprise applications are often structured around the concepts of business processes and business components. These concepts are addressed through a number of components, entities, agents and interfaces in the business layer.

In the MS-TLSA architecture the Business Layer has been split up in Service Interfaces, Business Workflow, Business Components and Business Entities. We’ll focus on this architecture style and the separation of the Business Components and Business Entities for the remains of this article. First let’s take a look at the MS-TLSA definition for the Business Components part.

Business components are the software realization of business concepts. They are the primary units of design, implementation, deployment, maintenance, and management for the life cycle of the business application. Business components encapsulate the business logic, also called business rules. These rules constrain the behavior of a business concept to match the needs of a particular company. For example, the business rule that determines whether a given customer is approved for a line of credit may be encapsulated in the customer business component for small solutions. For larger solutions, it is likely that all credit-related business logic is encapsulated in a separate credit component.

Sounds solid, right? Let’s do the same for the Business Entities.

Business entities are data containers. They encapsulate and hide the details of specific data representation formats. For instance, a business entity may initially encapsulate a recordset obtained from a relational database. Later, that same business entity may be modified to wrap an XML document with minimal impact to the rest of the application.

Business and business workflow components can interact with independent business entity components or they can use a business entity to set their own state and then discard the business entity. Business entities are often used as Data Transfer Objects [Fowler PoEAA]. The data access components will often return business entities instead of database-specific structures. This helps significantly in isolating database-specific details to the data layer.

So in the MS-TLSA approach Business Components and Workflow Components interact with Business Entities (DTO’s [Fowler PoEAA]). This means that the data and behavior that uses it is scattered throughout the software. Let me remind you that one of the fundamental concepts of object-orientation is to build applications out of objects that have both behavior and data. The MS-TLA architecture also violates the object modeling principle of turning information about a real-world entity and the actions performed on it into responsibilities of the object representing the entity. “Good object think” [Nicola et al. SOM] says objects act rather than get acted on, and conduct their own business rather than hold data for functional processing. While qualifying this statement as an object modeling principle and not an absolute law violation, it is a clear warning sign. The Microsoft .NET Pet Shop 4 application (probably already well known to you) is designed to show the best practices for building enterprise, n-tier .NET 2.0 applications. The concrete .NET Pet Shop architecture has its roots in the MS-TLSA architecture which is why we will use it as an example to demonstrate a reference implementation of this style of Business Layer.

In the .NET Pet Shop application customers use the check out web form to place their order. The check out web form creates a new OrderInfo Business Entity and fetches the LineItem Business Entities from the customer’s shopping cart. Next it asks the Order Business Component to process ordering logic which involves processing the customer’s credit card information (step 1), storing the order (step 2), calculating stock quantities (step 3) and storing the actual stock quantity (step 4). Please note that for the sake of clarity I left out the asynchronous strategy for processing the customer’s order. The following diagram captures a small part of the .NET Pet Shop implementation. 

MS-TLSA .NET Pet Shop check out process

MS-TLSA .NET Pet Shop check out process

I hope you directly notice the TakeStock(LineItemInfo[] items) method on both the Inventory Business Component and Inventory Data Access.

public void TakeStock(LineItemInfo[] items) {

 

    // Reduce the stock level in the data store

    dal.TakeStock(items);

}

Taking a closer look reveals that the Inventory Business Component TakeStock(LineItemInfo[] items) method just forwards the call to the Inventory Data Access to reduce the actual quantity in stock for an order its line items. The actual inventory logic is executed by the Inventory Data Access.

private const string SQL_TAKE_INVENTORY = "UPDATE Inventory SET Qty = Qty - ";

For this code to work properly it also needs to relate each line item and customer order quantity (step 5) with the order.

MS-TLSA .NET Pet Shop check out process

MS-TLSA .NET Pet Shop check out process

I think that it’s safe to say that the .NET Pet Shop check out logic is not only scattered over the Business Components and Business Entities implementations but also across the layers. In my experience this type of application often ends up being quite a tangled web of routines without a clear structure.

What if we’d agreed on having a deep model focus and to use the Domain Model Pattern [Fowler PoEAA] for structuring the check out logic of the .NET Pet Shop application? In a nutshell, the Domain Model pattern is an architectural pattern. Its intention is to capture knowledge in an object model that incorporates both behavior and data. It shines when dealing with complex business logic by its ability to solve domain-related problems in a web of interconnected objects, where each object represents some meaningful concept of the domain. For inspiration in designing a good domain model we’ll use the techniques for applying domain driven design as described in [Nilsson ADDDP].

DDD .NET Pet Shop check out process

DDD .NET Pet Shop check out process

This model solves the same problems/features as we talked about in the MS-TLSA architecture based .NET Pet Shop application example. In this model we speak of an isolated domain model in that it makes the check out concept explicit (step 1). The customers place their order using the check out web form, nothing different here. As opposed to the MS-TLSA architecture based .NET Pet Shop application where state of the order lines was kept in the shopping cart, now the state lives inside the model. The customer and credit card concepts are made part of the model, which makes it natural to make the CreditCard Domain Object responsible for charging the customers credit card (step 2). Reducing the quantity in stock for a particular product (step 4) is the responsibility of the Product Domain Object. This opens up a whole lot of possibilities in which the model acts as an enabler for new opportunities. Taking stock could cause infringements on the margin of critical safety or be used for calculations to determine a realistic safety margin. We now have full control over the check out logic. The first try could look like this:

public void CheckOut()

{

    // Handle credit card logic

    customer.CreditCard.Charge(TotalAmount);

    // Insert the new order into the system

    repository.AddOrder(this);

    // Update the inventory stock

    foreach(OrderLine line in orderLines)

    {

        line.Product.TakeStock(line.Quantity);

    }

}

I think this design is more maintainable in the long run because of its increased clarity and an implementation that is more true to the abstraction of the domain. Remember when I said earlier that the choice between MS-TLSA and DDD is a matter of taste? We have now come to the conslusion that this statement is wrong. It is a matter of choice how to organize domain logic in your applications. For making the right choice you will need to understand both alternatives equally well. What I find appealing about the model focus is that the resulting model is a great tool for communication amongst the stakeholders. The better the communication is, the better the software will become, both in the short and the long run.

I tried the model approach many times over the years and found problems with it, especially related to the performance overhead with instantiation time in the COM world. Another well known problem is the impedance mismatch between the relational and object-oriented worlds. With .NET we now have a much better toolbox that supports object-orientation. The next version of ADO.NET will enable a higher-level abstraction of data-access programming by introducing an entity model that brings conceptual-level data access concepts directly into the code. It includes a layer (ADO.NET Entity Framework Object Services) that can expose database data as regular .NET objects. This object layer makes an ideal target for LINQ support, allowing developers to formulate queries against a database right from the programming language used to build the domain logic. LINQ provides the run-time infrastructure for translating queries into SQL for execution by the database and then translating the tabular results back into the domain objects. I find it exciting to see that Microsoft is working on great tooling to support DDD. Even today, we can go a pretty long way with the current tools.

[Nilsson ADDDP]
Nilsson, Jimmy. Applying Domain-Driven Design and Patterns with Examples in C# and .NET. Addison-Wesley, 2006.

[Evans DDD]
Evans, Eric. Domain-Driven Design: Tackling the Complexity in the Heart of Software. Addison-Wesley, 2004.

[Fowler PoEAA]
Fowler, Martin. Patterns of Enterprise Application Architecture. Addison-Wesley, 2003.

[Microsoft TLSA]
Three-Layered Services Application
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpatterns/html/ArcThreeLayeredSvcsApp.asp

Microsoft .NET Pet Shop 4.0
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/bdasamppet4X.asp

Microsoft .NET Pet Shop 4: Migrating an ASP.NET 1.1 Application to 2.0
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/bdasamppet4.asp

[Nicola et al. SOM]
Nicola, Jill, Mark Mayfield, and Mike Abney. Streamlined Object Modeling: Patterns, Rules, and Implementations. New Jersey: Prentice Hall, 2002.

Comments

No Comments