Wednesday, September 13, 2006

Is Your Domain Model Generative ?

Martin Fowler defines a domain model as an object model of the domain that incorporates both behavior and data. If the domain is complex, then the domain model has to be complex and consequently the object model will also have to be rich and complex. Unfortunately some of the modern technologies (aka Entity Beans of J2EE) have encouraged a programming model where the domain model becomes anemic and the complexity of the domain sneaks into a procedural Service Layer. Martin Fowler's P of EAA and Erik Evans' DDD books talk enough of these anti-patterns and recommends all the virtues to have a behaviorally rich domain model in a layered architectural stack.

Generative Domain Models

Czarnecki and Eisenecker mention about another important attribute regarding richness of domain models - Generativity. A generative domain model is one that offers users the ability to order specific products or artifacts by specifying combinations of concrete implementations as configuration knowledge. More specifically
The key to automating the manufacture of systems is a generative domain model, which consists of a problem space, a solution space, and the configuration knowledge mapping between them.

What exactly do we mean by the model being generative ?

Apart from achieving high intentionality in modeling domain concepts, and promoting reusability and adaptibility, a generative domain model simplifies the process of manufacturing variants of a component / module through changes in externalized configuration knowledge. The model needs to have a unified architecture based on the commonalities of the domain with appropriate declarative hooks for plugging in variabilities.

Czarnecki and Eisenecker specify the following implementation techniques for generative models :

  • Generic Programming

  • Metaprogramming

  • C++ Template based programming

  • Aspect Oriented Programming


Of course, this is from a 1999 setting and we have many more popular programming paradigms practiced today which can promote generative domain model designs. In this post I will try to ruminate on some of these paradigms and practices and emphasize the importance of making models generative.

IoC using Spring

Spring, as an IoC container, offers strong bean management, with control over object lifecycle and dependency resolution. As configuration knowledge, it offers a DSL in the form of an XML, which the user can manipulate to wire specific implementations, inject new dependencies and weave new aspects. The user can program to interfaces and can *order* specific implementations through the DSL.

<bean id="myInventoryManager" class="org.dg.wire.InventoryManagerDefaultImpl"/>

<bean id="myProductManager" class="org.dg.wire.ProductManagerDefaultImpl">
  <property name="inventoryManager">
    <ref bean="myInventoryManager"/>
  </property>
  <property name="retrieveCurrentStock">
    <value>true</value>
  </property>
</bean>


In the above fragment of the configuration knowledge (the configuration XML of Spring), the user can declaratively supply implementations for myInventoryManager and myProductManager and control instantiations and lifecycle for all the Spring managed beans. I think this is generative domain modeling, where I can create concrete instances of my managed beans by providing implementation specific information to the configuration knowledge.

Te above example is a simplistic one and IoC containers generally provide many sophisticated features for complex bean management along with lifecycle semantics, scoped instantiations, constructor and setter based injections and dependency management. Add to that the complete declarative semantics through some form of DSLs (mostly XML based) - and you have the generativity non-intrusively weaved into your domain model.

Metaprogramming

One of the classic examples of a metaprogramming platform is Ruby on Rails, that offers amazing capabilities of generative modeling and programming. The abstraction of ActiveRecord in RoR provides a full-blown (well, almost) ORM framework for wrapping your database tables and providing access to all data and metadata. You just create a subclass of ActiveRecord::Base and you create an entire machinery to access all details of your database table.

class Order < ActiveRecord::Base
end


With just these 2 lines of code, RoR will create for you the entire model for Order, which maps to your database table Orders. RoR values convention-over-configuration - all conventions are stored in the configuration knowledge. You want to change 'em .. you are welcome .. just change ActiveRecord::Base.pluralize_table_names to false in environment.rb of the config directory and you can disable the pluralization of tables.

Traditional ORM frameworks use the mapping path, offering an object-oriented view of the world, while RoR employs the wrapping framework with a database-centric view of the world. But, whatever be it, RoR offers strong code generation capabilities using its metaprogramming engine. And the heart of it is, of course, the nice little DSL that it exposes to the world and allows users a rich set of configurability. It's generativity, at its best!

Aspect Oriented Programming

It is a well-established fact that the technology of AOP has been used extensively to address cross-cutting concerns of domain models. Transactions, security, logging, tracing, auditing etc. are best implemented in the domain model as aspects. Aspects are maintained separately from the codebase and are weaved dynamically (loadtime / runtime / compiletime) with the codebase. And because of this externalization, implementation of strategies can be changed declaratively within the domain model.

As an example, let us consider a model for a PaymentService, where the service needs to be controlled by a failover strategy. The actual implementation of the strategy can be externalized in the form of an aspect and weaved lazily with the model implementation. The following implementation has been adopted from Ramnivas Laddad's presentation at SpringOne.

public aspect PaymentServiceFailover {
  pointcut process(PaymentProcessorprocessor)
    : execution(*PaymentProcessor.*(..)) && this(processor);

  Object around(PaymentProcessorprocessor)
    : process(processor) {
      int retry = 0;
      while (true) {
        try {
        return proceed(processor);
        } catch(RemoteException ex){
          processor = getAlternativeProcessor(processor);
          ... give up logic ...
      }
    }
  }
  ...
}


Using Spring, we can inject the list of available processors declaratively and setup the complete configuration knowledge to use this specific failover strategy implementation.

public aspect PaymentServiceFailover {
  ...
  public setProcessors(List<PaymentProcessor> processors) {
    this.processors = processors;
  }
  private List<PaymentProcessor> processors;
  ...
}

<bean id="paymentServiceFailover"
  class="PaymentServiceFailover" factory-method="aspectOf">
    <property name="processors">
    <list>
      <ref bean="aProcessor"/>
      <ref bean="anotherProcessor"/>
    </list>
  </property>
</bean>


So, in the above example, we have successfully kept the implementation specific mappings externalized from the domain model. This results in the model being able to generate specific instances of PaymentService components with different implementations of failover strategies. Generativity !!

Conclusion

In summary, generative domain models offer more flexibility in practice. The invariant part of the domain resides within the model proper, while the variations are plugged into using DSLs as configuration knowledge. In practice there are many patterns to manage the variabilities within the scheme of the common architecture. But that's for another day. In the next post on domain models, I will talk about the benefits of a generative domain model in a layered architecture stack and how the service layer continues to shrink with a powerful domain model in place.

No comments: