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.

23 Comments

  • Thanks Paul - I'd like to see more of these types of articles.

    I read through Jimmy's book last month and was really impressed.

    Seeing more examples and approaches will help provide food for thought for those using the DDD.

  • Nice clarification, it would indeed be nice to see some more practical examples. Ordered the Nilsson book right after I read your article.


  • TheServerSide.NET

    Three-Layered Services Application v. DDD
    Posted by: Jack Vaughan on August 10, 2006

    Is it just style? Perhaps it is writes Paul Gielens.

  • Nice post Paul!
    Thanks.

  • But does it really work on complex object hierarchies? I have not had the luxury of working with systems where you could count the number of entities and their attributes on both hands (Order, Customer, LineItem and Product). I work in a world of entities, attributes and relationships that number in the low hundreds. I'll admit to understanding complex object hierarchies and relationships in terms of Forms and Controls where everything is held in memory. I've had a difficult time of justifying the reconstitution of an entire hierachy when only a portion of the data is need for the current operation (i.e. update the product quantity on hand). The domain model pattern makes sense to me in simple examples, but in practical terms the transaction script pattern is much more efficient and straight-forward. If you were somehow working in the database with object hierarchy and you weren't pulling it across process boundaries or machines, and the access was transparent, I would give it a second thought. For reference, storage wise, I've used everything from COBOL to CACHE (with the current RDBMS somewhere in the middle).

    Either way, great article. I like the focus and the direction. I hope to see more like it. I've been following Jimmy's work for some time (ever since his first book -- a total 180 from his current book) and was probably one of the first to order and read it. I was a bit disappointed. It was interesting, but very simplified. When I was finished, I was left with even more doubt than when I started it. I think Martin's POEA was a much better book. I've read bits and pieces of DDD, but to be honest... it's quite dry.

  • I guess what I'm trying to say, is that I rarely ever deal with an entire reconstruction of the object hierarchy. My database model is complex and contains entities with many attributes and deeply nested relationships.

    The same aggregates (Jimmy's definition) are not always used. In one use case, I may need a subset of the attributes and relationships. In another case, I may need a completely different subset of attributes and no relationships. It's hard to justify returning data that I don't need, and on the other hand I feel dirty about using partially allocated objects. The "only the data you asked for" mantra of the resultset (Recordset, DataSet, map, dictionary, array, etc) seems like a much better fit.

    Once again, in a system, where everything was in memory and there was no contention for data (single user system), a large object hiearchy (assuming it was small enough not to bog down the available RAM) seems to make more sense. But I'm primarily developing web based systems (separated from the database or application server) where more than one concurrent user is in session.

    Finally, (I started reading this article as I was flossing my teeth and heading off to bed) I find that a lot of the examples given in books and reference applications (like Pet Shop) have very simple business logic and don't really illustrate much more than shipping data in and out of the database. Most of the "business logic" layer of the Pet Shop example is just delegating the calls to the data access layer.

    My real feeling is that Microsoft will fail to make any significant impact with it's next version of ADO.NET. At worst, it will be another ObjectSpaces.

  • In response to Eric's comment, your work primary lies in session scope. In my experience, majority of types in this scope can be called presentation models and belong to different layer from core domain models.

    I underline two problems of importance. First is how to ensure transactional aspects in core domain model. Second is how to map between core domain model and presentation model to minimize logic duplication.

    Any ORM I know is using database for all of ACID properties (Genom-e probably less) following begin_tran, load, check_global_logic, change, store, check_constraints_logic, commit. In many cases it is slower then working entirely in database. On the other hand, any disconnected model must delegate to data acess layer to ensure serializability, like you observed in PetShop, or as I guess, in your work. In such case, you core domain logic is mixed with presentation logic, or duplicated.

  • Oh and I meant to say that I still think Jimmy's book is good, I just felt it wasn't deep enough on the bits that are important.

    Maybe someone needs to release a more detailed end to end DDD book, showing really practical examples and discussing (in detail) some of the issues that Jimmy's book only touches on (such as how to handle associations between aggregates when performance/contention are likely to be problems).

  • Colin: Very interesting! How would you feel about discussing the posible content of a "more detailed and to end DDD book"? Hit the email link on this page.

  • Hi Paul,

    I've sent an e-mail which you hopefully got.

    Ta,

    Colin

  • "M&P is the first "(Domain) Model Driven System" completely operational."

    "M&P allows the Direct Execution of the Specifications of Computer Applications without need of building Programs." 

    You should see it at:

    www.hdolder.com/PeBookRESEJECEN.htm

    Regards

    Charles

  • Hi,

    1) Which objects would be responsible for saving the credit card charge and the products that had their quantities changed?

    2) And which object would be responsible for doing it all in a transaction? The repository.addOrder() must be part of that transaction too.

    Thanks

  • 现在怎么跑出这么多中国话?
    全世界的人都在讲中国话,孔夫子的话越来越国际化。
    谢谢

  • The author mentions one flaw of MS-TLSA is that the business logic appears across different layers. To support this, the author shows the Order Business.Component communicating with a data access component. While this is true, the exact same thing would happen in a domain object. The "Order" object calls the repository. The repository is going to call some data layer. You can use a repository or provider model pattern in TLSA so as not to couple BL and DAL. Therefore, the comment "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.", makes no sense.

  • The idea of MS-TLSA is to provide layers and decoupling of UI components from the domain. Even in DDD you have an application service layer which buffers the domain model from UI and other consumers(which isn't mentioned in this article). In this DDD sample you also have checkout logic "scattered" over various domain objects. No different than scattering check logic over MS-TLSA business components and entities...so WTF?

  • Nice article but the image urls are all broken

  • searching for same blog engine

  • It's great to be great , but it's greater to be human.

    -----------------------------------

  • -----------------------------------------------------------
    "Virtuous what I used to be trying to find and very thoroughgoing as floor. Thanks for placard this, I noticed a yoke unique related posts but yours was the optimum so considerably. I outlook it stays up to date, appreciate worry."

  • -----------------------------------------------------------
    "As such, every time I browse a comparable write-up I only wish the particular OP incorporates some world wide web online video someplace."

  • Maybe Alcazzarre could help you to solve your problems? You'r welcome pal.

  • This is very fascinating, You're a very skilled blogger. I have joined your rss feed and look forward to seeking extra of your excellent post. Also, I've shared your web site in my social networks!

  • An individual built several advantageous facts presently there. I did searching with regard to inside the challenge and also noticed many men and females might agree inside your web page.

Comments have been disabled for this content.