Tuesday, February 17, 2009

6 months of DDD !

We have been learning and trying to use DDD in our project for the last 6 months. Meanwhile I got involved in a couple of other projects involving lucene, axis etc and had not looked at this code for quite some time.

I finally pulled in the sources to see how DDD had turned out and also find out if it was indeed helping in increasing the expressibility of code.

Some of the things that jumped out immediately were

  1. The request DTOs had seeped into the domain classes with certain domain methods that are called from service layer, accepting the request objects as inputs.
  2. Conditional checks (and logic) spread out. For e.g. a series of if-else checks with certain domain logic happening in each block.
  3. Large domain classes (in terms of LOC)
  4. All logic mainly in entities. No other kinds of domain objects (Value Objects, Services or specifications) were to be found.
  5. Mostly all entities have a shallow hierarchy structure. I am being generous here more than 90% of entities had no hierarchy.
We would now have to see how best to clean this up. Will keep you posted on how it goes.

Technorati Tags: ,

Subscribe to comments for this post

Monday, June 16, 2008

Domain Driven Design without AOP

Ramnivas Laddad, in this presentation during SpringOne, makes the assertion that "Domain Driven Design cannot be adequately implemented without help of AOP and DI".

I don't quite agree with this. I believe you can get by fine and do good DDD without using AOP.

According to the talk, AOP can be roughly used for the following purposes

  1. Dependency Injection in Domain entities and vo's
  2. Handling domain logic
  3. Handle Cross Cutting concerns
Of these, IMHO the only 'real' need for AOP is to handle cross cutting concerns like transaction management, auditing etc.

Dependency Injection without AOP

DI'ing services/policies/repositories into an Entity/VO can be done without using AOP in other simpler ways like
  1. Using callbacks methods like onLoad in Hibernate's Interceptor, which contains the injection logic based on the entity type. This is a slightly intrusive solution though.

    A better way is to have interfaces for each service/repository that is to be injected and making the entity implement the required interfaces.



    public interface OrderRepositoryAware {
         public void setRepository(OrderRepository orderRepo);
    }

    public interface CreditRatingAware {
         public void setCreditRatingSvc(CreditRatingSvc svc)
    }

    public class Order implements OrderRepositoryAware,CreditRatingAware { ... }

    public class DependencyInjectingInterceptor extends EmptyInterceptor {

         public boolean onLoad(Object entity,
            Serializable id,
            Object[] state,
            String[] propertyNames,
            Type[] types) {

              if(entity instanceof OrderRepositoryAware) {
                   ((OrderRepositoryAware) entity).setRepository(...);
              }
    ......

    }



    However the same logic needs to be replicated in Factory objects which creates new Entities. This is the drawback of this issue.


  2. Use a ServiceRegistry to get a reference to required service/repository etc. To unit test you just need to stub out ServiceRegistry.



    public class Order {
         public void validatePayments() {
              ServiceRegistry.getRepository().getPaymentHistory();
         }
    }


    The singleton initialization would have to change to create mocks when used in testing.
Domain Logic without AOP

In his presentation Ramnivas takes the example of a PaymentAuthorization service failure.
  1. If PaymentAuthorization fails, try authorizing using other service providers.
  2. In case all providers fail, do a temp auth based on payment history. When product is about to be shipped secure payment.
The example uses an around advice for PaymentProcessor.process which has retry logic. To do temp auth an Inter-type declaration is used.

In my mind, the clarity of code is vastly reduced by using AOP here. This domain logic that is weaved, is not be apparent and visible when looking at Order class. The domain class Order, is incomplete without considering the two aspects. This breaks the clarity of the code and model that is offered by DDD. There is no apparent gain using AOP here.

In this example, both aspects are core domain logic and in on real world model some object would have ownership of these bits of functionality. Either Order or a Domain Serice like OrderProcessSvc, would be the best objects to own this logic. Choosing between entity and service to host this logic, depends on whether the Order should own PaymentAuthorization (which I think it should) or not. But main thing is to encapsulate this logic into its rightful owner.


To me aspects in DDD can be used for things like enforcing rules (augmenting java's limited support for scoping - use an aspect that throws a compilation error whenever an entity is constructed using 'new' operator), handling service failures/issues etc at boundary with infrastructure services.

I believe Domain Logic should only be contained in POJOs to maintain clarity and readability. Any thoughts?


Technorati Tags: ,

Subscribe to comments for this post

Saturday, June 07, 2008

Associations in Domain Driven Design (DDD)

This post is part of a series I am writing on Domain Driven Design (DDD).

Associations between objects are typically not well thought out during design. Most of the time, the associations are dictated by the underlying data model. This results in addition of a lot of associations and traversal paths that may not make sense in a domain.

For e.g. an Order has an associations to multiple Products. Your natural traversal would be from an Order to Product. I am yet to see a usecase where you pick a product and 'traverse' to a list of Orders to which it is associated to. Normally the kind of functionality supported would be to list 'all open orders for product' or 'all orders for this product from a given customer' etc and these typically would be queried from DB using a DAO.

According to Eric Evans, associations should

  1. Impose a traversal direction
  2. Add qualifiers and reduce multiplicity
  3. Not be present if it is non-essential
Moving from a bi-directional association to a uni-directional association is one of my favourites since its generally easy to accomplish and offers biggest 'bang for buck' so to say. The other two are quite simple enough.

Unidirectional vs Bidirectional associations

A bidirectional association means that both Objects can only be understood together. There are real world usecases where such a necessity exists. For e.g. an Order needs to have a bi-directional association with its Settlement object. However in many cases like the first example a uni-directional association would suffice.

The advantages of unidirectional associations are
  1. It brings out the natural bias of the domain to one particular traversal direction
  2. Makes the association more communicative
  3. Provides a natural constraint on where to place domain logic since you can only place logic on the class which can reach out to all classes involved.
When to prefer Bi-directional over Uni-directional

However there were some scenarios where I started using unidirectional associations but in the end wound up reverting them to bi-directional since it felt more natural.
  1. Use Uni-directional associations if your usecases dictate there are multiple entry points for same operation.

    For e.g. an OrderList was initially modelled with a uni-directional association to list of Orders. Any domain logic that affects multiple orders can only be triggered from the OrderList.

    One of the usecases detailed that cancelling the last Order in a OrderList, cancels the entire list. Another usecase said that cancelling an OrderList should in turn call cancel on each Order within the list.

    If we had bi-directional associations, supporting the above 2 usecases led to some circular call issues.Order.cancel() calls OrderList.cancel() which internally would end up calling Order.cancel for all Orders ! One solution was to have Order.cancel and Order.doCancel where one would not trigger call to OrderList. This is plain ugly.

    The best solution is to make all cancel Order calls be handled by the OrderList. So let Order.cancel() delegate the cancel call to OrderList.cancelOrder(OrderToCancel).

    Since the Order does not have a back pointer to its OrderList, the Order had to use a repository to look up its OrderList. Moving to bi-directional we could use Hibernate's hydration support to get a reference to OrderList from Order and vice versa.

  2. Use Uni-directional association if there are usecases which require data from other object even though entry point is a different Object.

    The problem is compounded when having *-to-many relationships and many is actually quite a large number which causes a resource drag during Object hydration.

    For e.g. over course of a year, a single Customer can have thousands of Orders. Loading all Orders every time a customer object is created is bad for performance. But you would obviously need Customer data to fulfil a given Order and all Order data for a given customer to find credit worthiness.

    In such cases maintain a bi-directional association indirectly by having Customer.getOrders load Order data, on demand by querying from database.

Associations when modelled correctly ensure that there is always only one way to access data. This enhances readability and as a consequence maintainability of code.


Technorati Tags: ,

Subscribe to comments for this post

Tuesday, June 03, 2008

Alan Kay's Metaphor for OO

Alan Kay, one of the creators of SmallTalk has this to say about Object Oriented Programming


The most obvious parallel is the human body, which is divided into
trillions of cells, each performing its own specialized task.

Like objects in software produced with object-oriented programming,
human cells do not know what goes on inside one another, but they can
communicate nevertheless, working together to perform more complex
tasks. "This is an almost foolproof way of operating", Kay says.

By mimicking biology in this way, we can minimize many of the problems
inherent to the construction of a complex computing system. A developer
can focus on one simple module at a time, making sure it works
properly, and move on to the next. Not only is building a system this
way easier, but the system will be much more reliable. And when it does
break down, it is simpler to fix, because problems are typical
contained within individual modules, which can be repaired and replaced
quickly. By contrast, a monolithic system is like a massive mechanical
clock containing innumerable turning gears, none of which has its own
internal logic or communicates information. Each gear functions
unintelligently and only in relation to other gears. The design is
hopelessly flawed. When building gear clocks, eventually it
will reach a certain level of complexity and it falls in on itself.


Great crisp description. No cludgy words like blacboxes, blueprints etc. It clearly highlights the pitfalls in a procedural style of development.

I like the way in which he weaves in the concepts of Encapsulation(Info Hiding) and Message Passing.

Encapsulation is drilled into everyone doing OO. But most of the developers have still not got the subtle difference between message passing and method invocation. Can't say I blame anyone (i too did'nt know till recently), since you dont need to know about something they can't see/use when using java, c++ etc.

A message is a signal from one object to another that requests the receiving object to carry out one of its methods. The message consists of the name of the receiving object and its arguments, that is, the method it is to carry out and any parameters the method may require to fulfill its charge. Hence the end state of a message is "method invocation".

Ideally every object will get a message, check if it can respond to this message. If it can, the appropriate method for this message is invoked. Else the object can respond in whatever way it seems fit. When using Java this is not evident and not exposed at all. In Ruby atleast you have some access to this using the method_missing feature.

I digress. Coming back, I still remember my first OO concepts course, and the convuluted/over-simplified examples that were presented. I just wish I had come across stuff like this at that time.

Subscribe to comments for this post

Saturday, May 31, 2008

Domain Services in Domain Driven Design (DDD)

This post is part of a series I am writing on Domain Driven Design (DDD).

"A SERVICE is an operation offered as an interface that stands alone in the model, without encapsulating state, as ENTITIES and VALUE OBJECTS do." [Evans 2003]

The above defines what a Domain Service is. Any behaviour, operation or activity that cannot logically fit into an Object is a good candidate for being exposed as a service. However the important thing to note here is that the Service being exposed should represent a domain concept. This ensures you don't get carried away and create tons of services with very less entities and vo's.


Rules to be followed by Domain Services

A domain service has to abide by only 2 cardinal principles

  1. It has to be stateless
  2. It should have some meaning in domain e.g. AccountTransferService, AdjustOrderService etc

Identifying Domain Services


I carve out a service in any one of the following conditions
  1. The concept behind an entity/vo does not lend itself to the activity being modelled. If by adding the activity concerned the meaning of the entity/vo is diluted, the activity is better off exposed as a service. In other words, if there is no obvious owner expose behaviour as a service.

  2. When the activity being modelled spans across different entities/vo's that are not part of same aggregate, expose a domain service that co-ordinates the activity across the many objects involved.

    For e.g. when adjusting or modifying an existing order, the order, payment and delivery entities have to be updated. I find it more easier and intuitive to model this as a service rather than have all logic in Order.adjust method. To access and modify Delivery/Payment entities, Order entity may have to do a deep object graph traversal. The order entity may not always be qualified to handle this traversal. The OrderAdjustService however, would use a repository to look up all concerned entities and co-ordinate the adjust method among them. This ensures all domain logic of how adjusts happen is still contained within the entities and the service just acts as an orchestrator.

    In fact I like to have an Order.adjust method that the UI/Application layer calls. This Order.adjust method would then call the OrderAdjustService passing in required info. This provides a clean interface and separation of concerns.

  3. If a certain domain logic is applicable across multiple entities and you have to work with a single inheritance model (using java for example), then the logic can be exposed as a service.

    For e.g. multiple entities like Order, Shipment etc need to expose MarketPrice behaviour. The logic to create a price includes looking up real time market prices and currency conversion rates and then calculating the price. A MarketPrice service can encapsulates this logic. The entities should be able to refer the MarketPrice service and delegate all MarketPrice related calls to that service.

    I use this when a ValueObject cannot suffice. In this case there were no fields specific to market price in entities and these were runtime generated and consumed values.

    There is a good description of this technique here. However this is not commonly used.

FAQs on Services

  1. Are'nt Services bad and should'nt we use all objects as per OO ?

    Yes, Services tend to stand orthogonal to Object Oriented Design. Services are not always bad since its far worse to force fit a behaviour into some entity/vo just to be more OO compliant. It messes up the class by distorting its conceptual clarity and makes it harder to understand.

    There is a huge tendency in the modelling world to use excessive number of services. It's easy to stop fitting behaviour to appropriate class and instead stick them into meaningless services. This is when services become bad.


  2. What is an application service and how is it different from domain service ?

    An application service layer defines a set of services that act as boundary to the domain layer. Any interaction with the domain layer passes through these application services. The application services interface with domain and infrastructure layers to get the job done. The domain layer also can talk to infrastructure layer.

    Some excellent point about the distinction between the two can be found here and here.


  3. Can an application service directly talk to a domain service ?

    It depends on your preference on whether you want an explicit entity to own the operation or not.

    However one thing to be clear is that application service layer and domain service layer cannot be combined into one layer. It has been covered with good detail and explanations here and I will not go into them.

    My first take on this was that there is no reason for an application service to talk to domain service. However a colleague of mine had the view that if one service is going to call the other, then application service was not adding much value and it could pick up some of the work that domain service was doing.

    For e.g. our previous OrderAdjustService looks up a bunch of entities and calls appropriate methods on them. We got into an argument that if, this was all it did and had no special logic of its own then it may as well become an application service. However the methods being invoked in all cases were not exposed to application layer. So it was in this context we created a Order.adjust() method that delegated the call to OrderAdjust Service. Having Order.adjust() has an advantage that it makes Order own the adjust operation. If you are not particular about it, you could call OrderAdjustService from application service layer.

Domain services are an important part of Domain Driven Design since they give both flexibility and clarity to the model. As with all good things, use it with moderation !


Technorati Tags: ,

Subscribe to comments for this post

 
Clicky Web Analytics