BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage Articles Aspects of Domain Model Management

Aspects of Domain Model Management

This item in japanese

Bookmarks

Introduction

As can be learned from books such as Domain Driven Design [Evans DDD] and Applying Domain Driven Design and Patterns [Nilsson ADDDP], introducing the Domain Model pattern (Patterns of Enterprise Application Architecture [Fowler PoEAA]) into your application architecture may promise many benefits, but they do not come for free.

Using a domain model is rarely as easy as just creating the actual domain model classes and then using them. Soon enough one discovers that sizable amounts of infrastructure code will also be required in support of the domain model.

Prominent among the infrastructure demands that accompany a domain model is of course persistence - normally to a relational database. That's where Object/Relational (O/R) Mappers enter the picture. However, there's more to it than persistence. A large part of the infrastructure in a complex application will often be dedicated to managing the domain model objects during runtime. I refer to this part of the infrastructure as Domain Model Management [Helander DMM] or DMM for short.

Where Do We Put Our Infrastructure Code?

As the amount of infrastructure code grows, finding a good architecture for dealing with it all becomes increasingly important. A big part of the question is - are we allowed to put some infrastructure code in our domain model classes or is that something which should be avoided at all cost?

The argument for avoiding infrastructure code in the domain model classes is strong: The domain model is supposed to represent the core business concepts that our application is dealing with. Keeping these classes clean, lightweight and maintainable is an excellent architectural goal for an application that intends to make heavy use of its domain model.

On the other hand, as we will go on to see, taking the extremist route of keeping our domain model classes completely free of infrastructure code - often referred to as using a Plain Old Java/CLR Objects (POJO/POCO) domain model - can also prove problematic. It will often result in clunky, less efficient workarounds - and some features just won't be possible to implement at all that way.

This seems to indicate, as is so often the case, that we have a trade-off situation on our hands where we should try to put only just as much infrastructure code in our domain model classes as absolutely needed, but no more. We trade off some bloat in the domain model for some improved efficiency or enablement of some required Domain Model Management feature that wouldn't work otherwise. Negotiating good trade-offs is, after all, a large part of what software architecture is all about.

Time to Refactor

Unfortunately, the trade-off offered here might not be good enough to last you in the long run. The amount of infrastructure code that you will need to put in your domain model classes in order to support many of the most useful and powerful features is simply so big that your business logic code probably will drown before you have reached a production ready system.

That is, unless we can find a way to eat our cake and have it too. This article attempts to examine if we can find such a way to distribute the necessary infrastructure code over the domain model without actually littering the domain model classes themselves with any of this infrastructure code.

We will begin by looking at an application that puts all the relevant infrastructure code in the domain model classes. Then we are going to refactor the application, using only well known, tried and true object oriented design patterns, so that we end up with the same functionality as before but without littering the domain model classes with the infrastructure code. Finally we will look at how we can use Aspect Oriented Programming (AOP) to achieve the same effect in an even easier way.

But in order to see why AOP could be of any help to us when dealing with DMM requirements, we will begin by looking at how our code would look without it - first in the "rawest" form, where all the infrastructure code is placed in the domain model classes themselves and then in a refactored form where the infrastructure code has been factored out of the domain model classes - while still being distributed over the domain model!

Refactoring the Obese Domain Model

A lot of the runtime management of your domain model is based on interception - that is, as you access your domain model objects in your code, all your calls to the objects are intercepted by the features that so require.

An obvious example of this is dirty tracking. It could be useful to many parts of the application to know when an object has been modified but not yet saved (it is in a "dirty" state). The user interface could use this information to warn the user if they were about to discard any unsaved changes, whereas the persistence mechanism could use it to detect which objects actually require saving back to the persistent medium, thus avoiding having to save them all.

One way of doing this would be to keep copies of the original, unmodified versions of the domain objects around and to compare against them every time you wanted to know if an object had been modified. The problem with this scheme is that it is both wasteful of memory as well as slow. A more efficient approach would be to intercept all calls to the domain objects' setter methods so that whenever a setter method on an object is called, a dirty flag is raised for that object.

Where Do We Put The Dirty Flags?

We now run into the question of where to put the dirty flags. One option would be to place them in some dictionary structure, using the objects as keys and the flags as values. The problem with this is that we would then have to make that dictionary accessible to all parts of the application that might need it. We have already seen that this can include such different parts of the application as the user interface and the persistence mechanism.


Figure 1

Making the dictionary internal to either of these components would make it difficult to access for the others. In a layered structure, where lower layers cannot call higher layers (except for the central domain model which often resides in a shared, perpendicular layer that can be called by all other layers) it would necessitate putting it in either the lowest layer needing access to it (figure 1) or putting it in the shared, perpendicular layer (figure 2). Neither option is very attractive as it introduces undue coupling and an uneven distribution of responsibility between the components in your application.


Figure 2

A more inviting option, and one that goes well with object oriented thinking, would be to put the dirty flags on the domain objects themselves such that each domain object carries a Boolean dirty field indicating if it is dirty or not (figure 3). This way, any component that needs to know if a domain object is dirty can simply ask it.


Figure 3

So, part of the case for why we want to put some of the code for our infrastructure features in the domain model is that we want to be able to access these features from different parts of our application without unduly increasing the coupling. The UI shouldn't have to know how to ask the persistence component for the dirty flags and we prefer to invent as few perpendicular layers as possible in our layered application architectures.

This is an important reason, one that may be enough on its own for some to consider the approach we're about to examine in this article, but we will go on to see that there are others. But before we do so, let's take a glimpse at the other side of this argument - the reason why we may want to be restrictive about putting infrastructure code in our domain model classes.

The Obese Domain Model Anti-Pattern

Let's take a look at what a domain class might look like after you introduce a dirty flag as well as the interception required to raise it on the appropriate occasions. The example is in C# code.

public class Person : IDirty
{
protected string name;
public virtual string Name
{
get { return name; }
set
{
if (value != name)
((IDirty)this).Dirty = true;
name = value;
}
}

private bool dirty;
bool IDirty.Dirty
{
get { return dirty; }
set { dirty = value; }
}
}

public interface IDirty
{
bool Dirty { get; set; }
}
List 1

As can be seen from the example, the dirty flag is defined in an interface (IDirty) which is then implemented explicitly in the class. Explicit interface implementation is a nice C# feature that allows us to avoid cluttering the default API for the class with infrastructure related members.

This is helpful for example in the Visual Studio IDE where the Dirty flag will not show up in the code completion drop downs unless you explicitly cast to the IDirty interface. In fact, as can be seen in list 2, in order to access the Dirty property at all the object must first be cast to the IDirty interface.

The interception code in the example is limited to two lines of code (list 2). However, that's because we only have one property in our example so far. If we have more properties we'll have to repeat these two lines of code in each setter, each time modifying the comparison so that it is made against the appropriate field.

if (value != name)
((IDirty)this).Dirty = true;
List 2

So this wasn't too hard to write - and our domain model now supports dirty tracking in a way that is accessible to all components in the application that use the domain model and that is resource efficient and fast in that it doesn't require a copy of the unmodified version of the object being kept around.

The downside with this approach is that your domain model class is no longer strictly focused on the business concern it was meant to represent. Suddenly you have a lot of infrastructure code in it, making the actual business logic code harder to discern and the class itself more brittle, change-resistant and generally harder to maintain.

If dirty tracking were the only infrastructure feature that required (or could at least benefit from having) some infrastructure code inserted into the domain model classes, we might not be overly concerned. But this is unfortunately not the case. The list of such features goes on, but examples include the ones listed in table 1:

Dirty Tracking Object carries a Dirty flag showing if the object has been modified but not saved. Based on interception and introduction of new members (the dirty field and its getter and setter methods).
Lazy Loading Object state is not loaded until the first time the object is accessed. Based on interception and introduction of new members.
Original Value Tracking When a property is modified (but not saved) the object carries around a copy of the unmodified value. Based on interception and introduction of new members.
Inverse Property Management Property pairs representing a bi-directional relationship are automatically kept in synch. Based on interception.
Data Binding Object supports data binding interfaces and can thus be used in data binding scenarios. Based on introduction of new members (implementation of the data binding interfaces)
Replication Changes to objects are distributed to listening systems. Based on interception.
Caching Objects (or at least their state, see the Memento pattern [GoF Design Patterns]) are copied to local storage which is then queried instead of the remote data source in subsequent requests. Based on interception and introduction of new members.
Table 1

With all these features - and potentially more - relying on infrastructure code being added to your domain classes, the dream of a clean, maintainable domain model can suddenly seem remote.

I have described this problem, wherein the code in the domain model classes grows large enough as to become unwieldy, as the Obese Domain Model Anti-Pattern [Helander Obese Domain Model]. It provides a kind of counter-weight to the Anemic Domain Model Anti-Pattern [Fowler AnemicDomainModel] described by Martin Fowler, where the domain model classes contain too little logic.

In his description of the Anemic Domain Model, Fowler explains how it is a mistake - in fact, an anti-pattern - to put your business logic outside of the domain model, since it cannot then make full use of object oriented concepts and constructs.

I agree with his argument - I would even extend it to suggest that this goes just as much for the infrastructure code as for business logic code. The infrastructure code could also make use of OO concepts and constructs by being distributed over the domain model. By fiercely avoiding putting any infrastructure code in the domain model we therefore also run the risk of having this code fall prey to the issues associated with the Anemic Domain Model Anti-Pattern.

These limitations that spring from not allowing ourselves to add infrastructure code to the domain model - not fully utilizing OO - manifest in ways we have already seen: infrastructural features can become harder to share between different components in the application and we often end up with less efficient "workarounds", such as comparing against original values instead of doing interception based dirty tracking. There are even some features, such as lazy loading and inverse property management, which can not work at all without interception.

So, what is the solution, then? If we put all this infrastructure code in the domain model classes they become "obese" - hard to work with and maintain. But if we put it outside of the domain model classes, we get an "anemic" domain model where our infrastructure code can't make full use of the possibilities offered by object orientation.

We seem to be stuck between a rock and a hard place. Or, more specifically, we're stuck between an un-maintainable Obese Domain Model and a bunch of inefficient workarounds accompanying an Anemic Domain Model. This is obviously not a particularly nice place to be. It is time to address the age-old question: any ways to refactor ourselves out of this mess?

Using a Common Infrastructural Base Class

One idea would be to try to move as much as possible of this infrastructure code into a common base class which the domain model classes could then inherit from. The main problem with this, however, is that while it could be useful for introducing the new infrastructural members (such as the dirty flag) to the domain model classes, it doesn't provide us with the interception required for many of the features we want to support.

Another problem with the base class approach is that it may not provide the necessary level of granularity when it comes to controlling how features are applied. If different domain model classes have different infrastructure requirements we run into problems. We may be able to solve them by using a set of different base classes (perhaps inheriting from each other) but if we have single class inheritance, as is the case in C# and Java, we may not be able to do this if we also want to use inheritance in the domain model itself.

In order to see why this can become a problem, let's extend our example a bit to make slightly more "juicy": Let's say we should have a Person class which should have dirty tracking enabled and an Employee class which should have both dirty tracking and lazy loading enabled. Finally, the Employee class should inherit from the Person class.

If we were happy with putting our code right inside our domain model, we would now have a Person class looking like list 1 and an Employee class looking like list 3.

public class Employee : Person, ILazy
{
public override string Name
{
get
{
if (!loaded)
{
((ILazy)this).Loaded = true;

//call the persistence component
//and ask it to load the object
//with data from the data source
//(code omitted for brevity...)
}
return base.Name;
}
set
{
if (!loaded)
{
((ILazy)this).Loaded = true;

//perform lazy loading...
//(omitted)

}
base.Name = value;
}
}

private decimal salary;
public decimal Salary
{
get
{
if (!loaded)
{
((ILazy)this).Loaded = true;

//perform lazy loading...
//(omitted)

}

return salary;
}
set
{
if (!loaded)
{
((ILazy)this).Loaded = true;

//perform lazy loading...
//(omitted)

}

if (value != salary)
((IDirty)this).Dirty = true;

salary = value;
}
}

private bool loaded;
/// <summary>
///The Loaded property is "write-once" -
/// after you have set it to true you can not set
/// it to false again

///</summary>
bool ILazy.Loaded
{
get { return loaded; }
set
{
if (loaded)
return;

loaded = value;
}
}
}
List 3

As you can see, the bloat of infrastructure code threatening to drown the actual business concerns in the domain model classes has already started to creep upon us. This hint of the Obese Domain Model lurking in our future should motivate us to attempt a different approach - even if it may be one that demands a bit more effort up front. We do this since we hope a clean domain model will return that investment in maintainability and usability over the long term.

So, we begin by creating a DirtyBase base class which can provide the dirty flag and then we create a LazyBase base class which can provide a loaded flag. Working in a language with multiple implementation inheritance we could now let the Person class inherit from the DirtyBase class and the Employee could inherit from the DirtyBase and LazyBase classes, as depicted in figure 4.


Figure 4

But what if the language we want to use doesn't support multiple implementation inheritance? Well, the first thing we could do is to let LazyBase inherit from DirtyBase (see figure 5). That way we could still let the Employee class inherit the LazyBase class and still get both the dirty flag and the loaded flag. It might not be an optimal solution (what if we have an object that needs lazy loading but not dirty tracking?) but at least in this example case it could be an option.


Figure 5

However that still leaves us with the problem that the Employee class can't inherit from both the Person class and the LazyBase class in languages like C# and Java. The remaining option in these languages would be to create a base class containing both the dirty flag and the loaded flag (figure 6) and to let the Person class inherit a dirty flag it doesn't actually need.


Figure 6

So the base class approach has two problems: It doesn't provide the interception required for many features (dirty tracking and lazy loading included) and (at least on a single implementation inheritance platform) it leads to domain classes inheriting features they won't necessarily need.

Using Infrastructural Proxy Subclasses

Fortunately, OO offers an excellent way of killing both of these birds with just one stone. In order to provide both the interception and the granularity of control, all we have to do is to create subclasses which inherit from the domain model classes - one new subclass for every (concrete) domain model class.

The subclass can intercept the access to a member of its base class by overriding the member with a version that will begin by performing the interception related activities and then go on to pass on execution to the base class member.

In order to avoid having to create common infrastructure members (such as the dirty flag) in all the subclasses, they could still be put in a common base class that all the domain classes would inherit from, while features particular to a few classes could have the necessary members placed in the relevant subclasses (figure 7).


Figure 7

The common base class implements infrastructure members that are common to all domain model classes. Features that are not common to all domain classes get interfaces.

The domain model classes are clean from infrastructure code.

The proxy subclasses override domain class members to provide interception. They also implement infrastructure members that are not common to all domain classes.

Using a subclass in this way to provide interception is essentially an implementation of the Proxy pattern [GoF Design Patterns]. An alternative to using subclasses would be to use domain model interfaces - one per domain model class - which both the proxy class and the domain class could implement (figure 8).


Figure 8

The proxy class would then hold an instance of the domain class in an internal field and implement the domain interface by forwarding all calls to the hidden domain object. This is in fact the way the Proxy pattern is described in the original Design Patterns book by the Gang of Four [GoF Design Patterns] - but using subclasses is just as valid an approach.

The benefit of using subclasses is that you don't have to create a bunch of domain interfaces that might otherwise not be needed. There's also the advantage that code in a proxy subclass can call on code inherited from the domain class using the "this" keyword ("Me" in VB.NET) whereas the code in the interface based proxy will have to refer to the domain object via the internal field holding the reference to it. The subclass can also reach protected members that the interface based proxy would have to reach by reflection.

An additional twist on this issue is that with an interface based proxy, if you have a method in the domain class that returns a reference to "this", the effect will be that an "unproxied" instance of the domain object is returned to the calling code, meaning that features such as dirty tracking and lazy loading won't work on the returned instance.

Because of these issues I personally prefer the subclass based proxy approach, and this is the method we will continue to look at throughout this article. However, please keep in mind that all the techniques that will be discussed in this article could be implemented just as well using the interface based proxy approach.

The POJO/POCO Domain Model

If we compare the Proxy pattern based approach just discussed to our earlier example code in C#, our domain classes can now become completely clean, free of all infrastructure code, as can be seen in the beginning of list 4. All the infrastructure code has been moved to the base class and the proxy subclasses, shown at the end of the list.

//Domain Model Classes
public class Person : DomainBase
{
protected string name;
public virtual string Name
{
get { return name; }
set { name = value; }
}
}

public class Employee : Person
{
protected decimal salary;
public virtual decimal Salary
{
get { return salary; }
set { salary = value; }
}
}

//Infrastructure Base Class
public class DomainBase : IDirty
{
private bool dirty;
bool IDirty.Dirty
{
get { return dirty; }
set { dirty = value; }
}
}

//Infrastructure Proxy Subclasses
public class PersonProxy : Person
{
public override string Name
{
get { return base.Name; }
set
{
if (value != this.name)
((IDirty)this).Dirty = true;
base.Name = value;
}
}
}

public class EmployeeProxy : Employee, ILazy
{
public override string
{
get
{
if (!loaded)
{
((ILazy)this).Loaded = true;

//call the persistence component
//and ask it to load the object
//with data from the data source
//(code omitted for brevity...

}
return base.Name;
}
set
{
if (!loaded)
{
((ILazy)this).Loaded = true;

//perform lazy loading...
//(omitted)

}

if (value != this.name)
((IDirty)this).Dirty = true;

base.Name = value;
}
}

public override decimal Salary
{
get
{
if (!loaded)
{
((ILazy)this).Loaded = true;

//perform lazy loading...
//(omitted)

}
return base.Salary;
}
set
{
if (!loaded)
{
((ILazy)this).Loaded = true;

//perform lazy loading...
//(omitted)

}

if (value != this.salary)
((IDirty)this).Dirty = true;

base.Salary = value;
}
}

private bool loaded;
/// <summary>
/// The Loaded property is "write-once" -
/// after you have set it to true you can not set
/// it to false again

/// </summary>
bool ILazy.Loaded
{
get { return loaded; }
set
{
if (loaded)
return;

loaded = value;
}
}
}
List 4

By employing the Proxy pattern, potentially in combination with a common base class, we can successfully address all the issues we have looked at and which have so far taunted us either from the direction of the Anemic or the Obese Domain Model Anti-Pattern:

  • We are able to distribute relevant parts of our infrastructure over the domain model so that it is easy to access by all parts of our application and so that it can be implemented in an object oriented and efficient manner.
  • We are able to distribute as much infrastructure code as we like over the domain model without running the risk of ending up with an Obese Domain Model. In fact, the code in our actual domain model classes can remain totally clean, focusing entirely on the business aspects they are trying to capture.
  • We can mix and match, adding only the infrastructure code required to each domain model class.
  • We can build features that are based on interception.

It should be noted that using a strict definition of POJO/POCO, our domain model classes should not inherit from an infrastructural base class. However, we can avoid this by moving all of the logic from the common base class to the proxy subclasses - that way we end up with a completely POCJO/POCO domain model. If that is a requirement than it is easily realizable with our approach, it is just a bit more work. If it is not a requirement we can use the base class and still see that the code in our domain model classes is completely free of actual infrastructure code.

So, at this point we have an architecture that allows us to combine completely POJO/POCO domain model classes with the goal of distributing our infrastructure code over the domain model. We can also take the "semi-POJO/POCO" route of using a common base class, saving ourselves some work if our goal is merely to avoid an obese domain model and not necessarily fulfill the definitions of POJO/POCO.

Using the Abstract Factory Pattern

This sounds wonderful, right? Are there no issues at all with this approach, then, you may wonder. Since the software business can make people cynical, chances are you will actually suspect a nasty problem or two to rear their ugly heads, right about now.

And you'd be right. Two matters for concern do present themselves immediately. The first one is fairly minor: In order for the subclasses to be able to override the members of the domain model classes and provide interception, all the domain model members must be made virtual (or at least all the ones you want to be able to intercept).

The second issue is potentially worse: Since you want your application to work with instances of your proxy subclasses, you must visit all the places in your application code where you create a new instance of one of your domain model classes and modify it so that an instance of the relevant proxy subclass is created instead.

If that sounds like half a nightmare plus change to do in an already existing application, well, then that's because it is. There is only one way to avoid this massive search and replace operation and that is to avoid using the "new" keyword for creating instances of your domain model classes from the very beginning.

A traditional way of avoiding "new" is to make use of the Abstract Factory pattern [GoF Design Patterns]. Instead of letting client code create instances using "new" they call a Create() method on a Factory class. The Create() method is responsible for making the call to "new" and it may also do additional setup related operations to the new instance before returning it.

The wonderful part if you have used the Abstract Factory pattern throughout in your calls to the domain model is that you will then be able to modify just one place in your code - the Factory class - changing it from returning instances of the domain classes to returning instances of the proxy subclasses (or interface based proxies for that matter).

This is a heavy argument for using the Abstract Factory pattern for all your domain object instantiation - at least in languages such as Java and C# that don't allow exotic features such as overloading the member access operator like C++, changing the behavior of the "new" keyword like ObjectiveC or modifying classes at runtime like Ruby.

Reflecting On Inheritance

There is one more issue worth mentioning with the Proxy subclass approach. While it is really a corner case scenario, it is fairly subtle and can therefore bite you bad if you do run into it without knowing what's causing it.

If you take a look at figure 9 you'll notice that the Employee class inherits from the Person class, just as it should: whenever a method expects a Person object, passing an Employee object should work just as well. Furthermore, the PersonProxy class inherits from the Person class. This is also good because that means that it is "legal" to pass a PersonProxy object as a parameter to a method expecting a Person object.


Figure 9

In the same way, the EmployeeProxy inherits from Employee, meaning that you can pass an EmployeeProxy object to any method expecting an Employee object. Finally, since EmployeeProxy inherits from Employee and Employee inherits from Person, this means EmployeeProxy inherits from Person. Thus, any method expecting a Person object will also accept an EmployeeProxy object.

All this is just as we would hope and expect. It is important to us that when our Abstract Factory suddenly starts returning proxy objects rather than plain instances of the domain model classes our client code continues to function as normal, without having to rethink they way our type hierarchies need to be handled.

In other words, if we have a method expecting a Person object to which we used to (legally) pass an Employee object, our code must continue to compile (and work) when we suddenly pass it an EmployeeProxy object instead. Fortunately, since EmployeeProxy inherits from Employee, and Employee inherits from Person, this will continue to work fine.

In fact, everything will continue to function just dandy when you start using the proxies instead of the domain model objects, just as one would hope. Everything, that is, except for one tiny little thing.

The red inheritance line in figure 9 is meant to symbolize that EmployeeProxy does not inherit from PersonProxy. When might this present a problem?

Well, consider a method that accepts two objects and that proceeds to use reflection to determine of one of the objects belongs to a subclass of the other object. When we passed a Person object and an Employee object to this method, it would return true. But when we pass a PersonProxy object and an EmployeeProxy object to the method, it would suddenly return false.

Unless you have reflection based code that inspects inheritance hierarchies, you should be safe. But in case you do, it doesn't hurt to be aware of this caveat (which you will then be able to get around by modifying your reflection code so that it detects proxies and steps up the type hierarchy until it finds an unproxied type).

Using Mixin and Interceptor Classes

We have come a long way towards a maintainable domain model architecture that will allow for a capable, efficient and accessible infrastructure for runtime Domain Model Management.

Could we do even more?

Let's begin by taking a look at those features that should be applied only to some domain classes but not to all - the features where we need to put the required infrastructure members in the proxy subclasses rather than in the shared base class. In our example the loaded flag for the lazy loading feature will have to be added to the subclass of every class that needs to support lazy loading.

Because we potentially need to put the same code in multiple subclasses, we run the obvious risk of ending up with code duplication. In the case of just one flag this may not be too bad, but what about a feature that needs several fields and perhaps even methods with complicated implementations?

In our example the loaded flag is write-once, so that after it has been switched to true it can't be switched back. Accordingly we have some code in the setter method to enforce this rule - code which we would need to repeat in the setter method for the loaded flag in the subclass of each and every domain model class that needed lazy loading.

What we would like to do is to create a reusable class containing this logic. But we have already used up the inheritance (still assuming we work on a single inheritance platform) so how can this lazy loader class be reused?

One good answer is to use the Composite pattern [GoF Design Patterns] rather than inheritance for this. Using this pattern, the EmployeeProxy subclass would contain an internal field with a reference to an instance of the reusable lazy loader class (figure 10).


Figure 10

The reusable class is often referred to as a mixin, reflecting the fact that implementation is being mixed in to the type rather than being part of the inheritance hierarchy. The effect of using mixins is a lot like being able to use multiple implementation inheritance in a single implementation inheritance language (or even on a platform that only supports interface inheritance, such as COM+).

An interesting side note to this discussion is that using our composition approach, behavior and state in the form of mixins can be dynamically mixed in to target classes (using Dependency Injection) rather than being statically bound to targets (as would be the case if the behavior in question were inherited). While we won't look more at how this potential can be exploited in this article, it opens up a wide range of opportunities for supporting very flexible and dynamic scenarios.

By breaking out the members introduced by the subclass into a reusable mixin class we take one further step towards a truly modular, coherent and cohesive architecture with low coupling and high potential for code reuse. Can we go even further in this direction?

Well, the next thing to do would be to break out the interception code from the subclasses and put that as well into reusable classes. These interceptor classes would be contained by the proxy subclasses in the same way as the mixins, as shown in figure 11.


Figure 11

The Person, Employee and DomainBase classes remain unchanged since the last version of the code, but the PersonProxy and the EmployeeProxy classes have changed, and we have introduced two new interceptor classes and one new mixin class. List 5 shows how the code looks after we have performed these refactorings (excluding the unmodified classes).

//These proxy subclasses contain only boilerplate
//code now. All actual logic has been refactored
//out into mixin and interceptor classes.

public class PersonProxy : Person
{
private DirtyInterceptor
dirtyInterceptor = new DirtyInterceptor();

public override string Name
{
get { return base.Name; }
set
{
dirtyInterceptor.OnPropertySet(this, this.name, value);
base.Name = value;
}
}
}

public class EmployeeProxy : Employee, ILazy
{
//This mixin contains the implementation
//of the ILazy interface
.
private ILazy lazyMixin = new LazyMixin();

private LazyInterceptor lazyInterceptor = new LazyInterceptor();
private DirtyInterceptor dirtyInterceptor = new DirtyInterceptor();

public override string Name
{
get
{
lazyInterceptor.OnPropertyGetSet(this, "Name");
return base.Name;
}
set
{
lazyInterceptor.OnPropertyGetSet(this, "Name");
dirtyInterceptor.OnPropertySet(this, this.name, value);
base.Name = value;
}
}

public override decimal Salary
{
get
{
lazyInterceptor.OnPropertyGetSet(this, "Salary");
return base.Salary;
}
set
{
lazyInterceptor.OnPropertyGetSet(this, "Salary");
dirtyInterceptor.OnPropertySet(this, this.name, value);
base.Salary = value;
}
}

//The ILazy interface is implemented
//by forwarding the calls to the mixin,
//which contains the actual implementation
.
bool ILazy.Loaded
{
get { return lazyMixin.Loaded; }
set { lazyMixin.Loaded = value; }
}
}

//The following mixin and interceptor classes
//contain all the actual infrastructural logic
//associated with the dirty tracking and
//the lazy loading features.

public class LazyMixin : ILazy
{
private bool loaded;
/// <summary>
/// The Loaded property is "write-once" -
/// after you have set it to true you can not set
/// it to false again

/// </summary>
bool ILazy.Loaded
{
get { return loaded; }
set
{
if (loaded)
return;

loaded = value;
}
}
}

public class DirtyInterceptor
{
public void OnPropertySet(
object obj,
object oldValue,
object newValue)
{
if (!oldValue.Equals(newValue))
{
IDirty dirty = obj as IDirty;
if (dirty != null)
dirty.Dirty = true;
}
}
}

public class LazyInterceptor
{
public void OnPropertyGetSet(object obj)
{
ILazy lazy = obj as ILazy;
if (lazy != null)
{
if (!lazy.Loaded)
{
lazy.Loaded = true;

//perform lazy loading...
//(omitted)

}
}
}
}
List 5

By refactoring so that all the actual infrastructure logic ends up in mixins and interceptor classes, the proxy subclasses turn into fairly slim, lightweight classes that focus on forwarding calls to the interceptors and mixins. In fact, at this point the proxy subclasses consist of nothing more than boilerplate code that could easily be generated by a code generation tool.

One option would be to generate the code for the proxy subclasses at design time, but languages like C# and Java allow that you generate, compile and execute code at runtime. Therefore we also have the option of generating the proxy subclasses at runtime, a practice that is commonly known as runtime subclassing.

Take a moment to reflect over how far we have come. In the first step we were able to refactor our way from an Obese Domain Model to a POJO/POCO Domain Model using proxy subclasses (and, optionally, a base class) in such a way that the infrastructure code could still be distributed over the domain model. In the second step we refactored all the actual infrastructural logic away from the proxy subclasses and into reusable mixin and interceptor classes, leaving only boilerplate code in the proxy subclasses.

In the final step we turn towards generating the full code for the boilerplate proxy subclasses using a runtime code generator. And at this point we have come all the way to the land of Aspect Oriented Programming.

Using Aspect Oriented Programming

For the longest time I felt curious about all the AOP hoopla only to become completely mystified every time I tried to read up on what it was all about - mainly because of the insistence by the AOP community on using such weird terminology. It also doesn't help that it often feels like some (not all!) AOP advocates seem to go out of their way to make the subject appear excitingly different and, well, intimidating.

Thus it may come as a surprise to you to learn that if you have read this far, you have in fact already grasped all the major concepts of Aspect Oriented Programming - and you've been given an idea about how an AOP framework can work under the hood, to boot.

Aspect Oriented Programming uses the central concept of an aspect, which is simply a collection of introductions (mixins) and advice (interceptors). The aspect (the interceptors and mixins) can be applied to your existing classes at runtime using, among other possible techniques, runtime subclassing.

As you can see, you already have an understanding of most of the weird but important AOP terms. The term crosscutting concerns that is used a lot to describe what aspects are good for simply means that you have a feature that should be applied to a lot of classes (that don't necessarily share an inheritance hierarchy) - such as our dirty tracking and lazy loading features which are concerns that are crosscutting across the domain model.

The only really important AOP terms we haven't really covered so far are join points and pointcutting. A join point is a place in a target class to which you can apply an interceptor or a mixin. Normally the join points of interest for interceptors are the methods while the join points of interest for mixins are the classes themselves. A join point is, in a nutshell, a point where you can join in your aspects.

In order to define which aspects that should be applied to which join points, you use a pointcutting language. This language can be something simple such as a declarative language where you might just name aspect and join point combinations in an xml file, but can sometimes also allow for more advanced "pointcutting" (targeting of join points) using regular expressions or even fully blown Domain Specific Languages.

So far, pointcutting has not been a concern for us since we have manually applied our aspects (our mixins and interceptors) exactly where we wanted them. But if we want to take the final step to using an AOP framework for applying our aspects we need to consider this subject as well.

But before we do, let's pause to ponder what is being proposed. Using an AOP framework at this point, after the refactorings we have done, is actually not at all a drastic step. It is a very small step, since we have already effectively refactored our application into using aspects in the form of interceptors (advice) and mixins (introductions).

In fact, I would suggest that at this point we are in effect using AOP - we're just not using an AOP framework to automate the boilerplate parts for us yet. But we are using all the essential concepts from AOP (interception and mixins) and we're doing it in a reusable way addressing crosscutting concerns. That sounds like the very definition of AOP, so it shouldn't be surprising that an AOP framework could help us automate some of the work we'd otherwise have to do manually.

The code we currently have in our interceptor and mixin classes can be minimally modified to work as aspects - it has already been refactored into a generic, reusable form which is just how aspects are supposed to be written. The only thing we would need the AOP framework to do is to help us apply our aspects to the domain model classes in some way. As mentioned, there are many ways to do this for the AOP framework, but one way is to generate proxy subclasses at runtime.

In the case of a runtime subclassing framework, the code for the generated proxy subclasses will look a lot like the boilerplate code in the proxy subclasses in our example. In other words, it is easily generated. If you think you could write a code generator up to the task, you're halfway towards implementing the engine for your very own AOP framework.

Refactoring to Aspects

In our final refactoring, we will take a look at how our example application will look if we use an AOP framework to apply our interceptors and mixins. In this example I will use NAspect, the open source AOP framework for .NET that Roger Johansson and I have written together. NAspect uses runtime subclassing to apply the aspects.

Having read thus far you'll have no trouble understanding the "magic" that NAspect performs - it simply generates a proxy subclass with the boilerplate code required for forwarding calls to mixins and interceptors and it uses standard object oriented overriding of domain class members to provide the interception.

Many people associate AOP with voodoo magic of the worst kind. If the bizarre terminology is not enough to discourage them, the way things happen suddenly and "invisibly" in interceptors without the developer being able to see it in the domain class code will strike many as deeply discomforting, almost offensive.

It helps to get a concrete understanding of what the terms mean, of course. It also helps to understand at least one way that the aspects can be applied and to see that it isn't really a question of magic - just a few good old, well known, object oriented design patterns at work.

AOP is all about using well known OO patterns in a way that lets us address cross cutting concerns. An AOP framework is just a thing that lets you apply your aspects more comfortably than by having to manually write a lot of proxy subclasses yourself.

So, now that we're not intimidated by AOP anymore, let's look at how we can use it to bring our application that final step to the goal line.

The first thing we do, in this case, is to include a reference to the NAspect framework assembly. When we have that in place, we can begin creating our aspects and defining our pointcuts. We can also go ahead and delete our PersonProxy and EmployeeProxy classes - from now on, NAspect will generate those classes for us.

We can even delete the DomainBase base class if we like - there's no need to use a base class to apply mixins that are common to all the base classes, we might as well do that too using the AOP framework. This means that by using an AOP framework we're able to meet even the strict requirements of POJO/POCO without any additional work.

In order to get rid of the base class, we just move the functionality into mixins. In our case we just need to create one more mixin - the DirtyMixin, which holds the dirty flag that previously resided in the base class.

The code in the LazyMixin class can remain entirely unmodified so it will not be listed. In fact, all we really need to do is to create the new DirtyMixin class and to modify the code in the two interceptor classes slightly, to make them work with the data structure representing the intercepted method which is passed to them by NAspect.

We also need to modify our factory class so that it uses NAspect to create proxy subclasses for us. This is assuming we have already gone over to using the Abstract Factory pattern everywhere in our application. If we had not yet done so, we would certainly learn our lesson now since without the Abstract Factory pattern, we would have to undertake another huge search and replace operation, going over each place in the code where proxy subclasses were being instantiated and changing to calls to the NAspect runtime subclassing engine.

The refactored code, ready for use with NAspect, is shown in list 6.

public class DirtyMixin : IDirty
{
private bool dirty;
bool IDirty.Dirty
{
get { return dirty; }
set { dirty = value; }
}
}

public class DirtyInterceptor : IAroundInterceptor
{
public object HandleCall(MethodInvocation call)
{
IDirty dirty = call.Target as IDirty;

if (dirty != null)
{
//Extract the new value from the call object
object newValue = call.Parameters[0].Value;

//Extract the current value using reflection
object value = call.Target.GetType().GetProperty(
call.Method.Name.Substring(4)).GetValue(
call.Target, null);

//Mark as dirty if the new value is
//different from the old value

if (!value.Equals(newValue))
dirty.Dirty = true;
}

return call.Proceed();
}
}

public class LazyInterceptor : IAroundInterceptor
{
public object HandleCall(MethodInvocation call)
{
ILazy lazy = call.Target as ILazy;

if (lazy != null)
{
if (!lazy.Loaded)
{
lazy.Loaded = true;

//perform lazy loading...
//(omitted)

}
}

return call.Proceed();
}
}

public class Factory
{
public static IEngine engine = ApplicationContext.Configure();

public static Domain.Person CreatePerson()
{ return engine.CreateProxy<Domain.Person>();
}

public static Domain.Employee CreateEmployee()
{
return engine.CreateProxy<Domain.Employee>();
}
}
List 6

In order to know which classes to apply your aspects to, NAspect uses (among other options) an xml configuration section in the application configuration file. At this point we could define our aspects in xml by pointing out the types of our mixin and interceptor classes as well as the types we want to apply them to. In principle, we are ready to try out our AOP application.

However, there is one thing that can still make many developers hesitant about using AOP, even when they understand the terminology and the theory behind AOP well, and that is the fragility that comes with a weakly defined pointcutting system.

While we could define a few clever regular expressions that would let us target just the classes and members we wanted to apply our aspects to, chances are you would forget to update your pointcut specifications when your domain model changes and so suddenly your regular expression would target classes that the aspects should not be applied to. This is just the type of thing that gives AOP a bad reputation as a voodoo technology.

One way of dealing with this pointcutting imprecision is by creating custom .NET Attributes (annotations in Java). By decorating the domain model classes with custom attributes and then using the attributes as pointcut targets we avoid the hocus pocus of using regular expressions and the like for applying our aspects. Aspects are only applied where we consciously decide to apply them by putting attributes there.

So in our case, we go on by creating two custom attributes - LazyAttribute and DirtyAttribute - that we then use to decorate our classes (list 7).

public class DirtyAttribute : Attribute
{
}

public class LazyAttribute : Attribute
{
}

[Dirty]
public class Person : DomainBase
{
protected string name;
public virtual string Name
{
get { return name; }
[Dirty]
set { name = value; }
}
}

[Dirty]
[Lazy]

public class Employee : Person
{
protected decimal salary;
public virtual decimal Salary
{
[Lazy]
get { return salary; }
[Dirty]
[Lazy]

set { salary = value; }
}

public override string Name
{
[Lazy]
get { return name; }
[Dirty]
[Lazy]

set { name = value; }
}
}
List 7

We finally go on to define our pointcuts in the application configuration file (list 8) so that our aspects target our custom attributes.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>

<section
name="naspect"
type="Puzzle.NAspect.Framework.Configuration.NAspectConfigurationHandler, Puzzle.NAspect.Framework.NET2"/>

</configSections>

<!-- Puzzle.NAspect.Framework settings -->
<naspect>
<configuration>

<aspect
name="DirtyAspect"
target-attribute="InfoQ.AspectsOfDMM.Attributes.DirtyAttribute, InfoQ.AspectsOfDMM" >

<pointcut
target-attribute="InfoQ.AspectsOfDMM.Attributes.DirtyAttribute, InfoQ.AspectsOfDMM" >

<interceptor
type="InfoQ.AspectsOfDMM.Aspects.DirtyInterceptor, InfoQ.AspectsOfDMM" />

</pointcut>

<mixin type="InfoQ.AspectsOfDMM.Aspects.DirtyMixin, InfoQ.AspectsOfDMM"/>

</aspect>

<aspect
name="LazyAspect"
target-attribute="InfoQ.AspectsOfDMM.Attributes.LazyAttribute, InfoQ.AspectsOfDMM" >

<pointcut
target-attribute="InfoQ.AspectsOfDMM.Attributes.LazyAttribute, InfoQ.AspectsOfDMM" >

<interceptor
type="InfoQ.AspectsOfDMM.Aspects.LazyInterceptor, InfoQ.AspectsOfDMM" />

</pointcut>

<mixin type="InfoQ.AspectsOfDMM.Aspects.LazyMixin, InfoQ.AspectsOfDMM"/>

</aspect>

</configuration>
</naspect>
</configuration>

We're now finally ready to try out our AOP application. When we run the application, NAspect will generate proxy subclasses for us at runtime and insert the boilerplate code in the subclasses to forward all calls to your interceptor and mixin classes.

The final architecture for our application can be seen in figure 12. Note that the only actual difference between this version and our earlier, non-AOP version, is that the two proxy classes (marked with broken outlines) will now be generated by the AOP framework, whereas before we had to code them manually.

Compared to figure 11 we have an additional DirtyTrackerMixin class and a new IDirtyTracker interface replacing the DomainBase base class, but this is just what we would have had without using AOP as well, had we decided to go without the common infrastructural base class (meeting stricter POJO/POCO requirements). In other words, if we don't want to use a common base class, we end up with exactly the same architecture (the one shown in figure 12) regardless of whether we use an AOP framework or not.

Figure 12

Pointcutting Options

When you add new domain model classes to the mix, all you need to do in order to enable lazy loading and dirty tracking for them is to decorate them with the custom attributes and the features will be applied to them "automagically".

sing attributes/annotations as pointcutting targets, you'll quickly note that using one attribute per feature that you want to apply has a tendency of producing an awful lot of attributes per member in your domain model. Thus, to reduce the number of attributes you might want to look for abstractions between them.

Another option, if you feel comfortable with a regular expression based pointcutting approach and you feel that littering the domain model with attributes compromises the goal of keeping it completely free of all infrastructure concerns, you can just configure your xml configuration file to match the relevant target classes and will not need to decorate your domain classes with custom attributes.

Alternatively, the xml pointcutting language of NAspect (as of many other AOP frameworks) allows you to simply supply a full list of the types that an aspect should apply to, avoiding the need to find a regular expression that somehow matches just the right classes. This makes for a more verbose configuration file, but allows your domain model to remain completely clean.

An additional benefit from using an AOP framework where you use pointcutting to apply your aspects dynamically is that it becomes easy to apply different aspects to the same classes when they are used in different use cases. If one use case requires lazy loading for a certain domain class while another use case doesn't, only the first use case would have to use a configuration file that applies the lazy loading aspect.

This dynamic application of aspects can be very powerful, not least in testing scenarios where additional testing aspects can be applied, for instance to provide mocking capabilities.

Conclusions from using Aspect Oriented Programming

We started with the question of whether we were allowed to put any of our infrastructure code in the domain model. We saw that this was certainly desirable since it allowed for more efficient implementation of many features, but that it threatened to make our domain model "obese".

To solve this issue we refactored our obese domain model - first by moving the infrastructure code into proxy subclasses and a base class, then by moving the actual logic out of those proxy subclasses and into mixins and interceptor classes. This made our domain model buff but we ended up with a lot of boilerplate code to write in the proxy subclasses. In order to solve this we turned to Aspect Oriented Programming.

The step to using an AOP framework turned out to be so small - in fact our application architecture didn't change one bit - that it probably came as a surprise to some readers, who may even experience that familiar feeling that often comes when you understand a design pattern for the first time and you realize it is something you've done often but without knowing it had a name.

You may well have effectively been doing AOP in many of your applications without realizing it and without, as it were, using an AOP framework to help you automate some of the boilerplate code generation.

We are now at the end of this article and hopefully at this point you'll agree with me that:

  • AOP isn't as hard or confusing as it looks, and using an AOP framework is easy.
  • Regardless of whether you use an AOP framework, using AOP concepts and modeling techniques is still a great way for handling the crosscutting Domain Model Management concerns in your application infrastructure.

It's really all just a matter of refactoring your way towards steadily improving your application architecture, using good old fashioned OO patterns. When doing so, don't be afraid to move towards an application architecture that could be described as Aspect Oriented, using proxies to apply interceptors and mixins.

Whether you then go on to let an AOP framework help you with applying your aspects doesn't really affect weather you're doing AOP or not. Because, if you are refactoring your application along the lines discussed in this article, you are doing AOP - with or without the help of a framework.

Summary

By refactoring our Obese Domain Model using traditional, well known object oriented design patterns such as the Proxy pattern, the Abstract Factory pattern and the Composite pattern, we arrived at an application architecture that elegantly combines a lean domain model with an infrastructure that can take full advantage of object oriented concepts and constructs. This way, we neatly avoided falling in neither of the Obese Domain Model nor the Anemic Domain Model Anti-Pattern traps.

Employing the patterns in the way discussed in this article leads to an application architecture that could well be described as Aspect Oriented. This is because we end up with mixin and interceptor classes that address our crosscutting concerns, closely matching the introduction and advice concepts found in Aspect Oriented Programming.

If you want to see for yourself that using AOP is really this fun and easy, but you wouldn't mind not having to type in all the code, you can download the full code from this article in the accompanying Visual Studio 2005 project.

In summary, in this article I have tried to show how Aspect Oriented concepts and tools can provide a great way of thinking about and applying many of your Domain Model Management concerns and how they help greatly in mitigating the risk of the Obese Domain Model Anti-Pattern.

About the author

Mats Helander works for Avanade Netherlands as a Senior Software Development consultant. In his free time he has developed the Puzzle.NET suit of free, open source frameworks and tools together with Roger Johansson. Puzzle.NET includes NPersist and ObjectMapper (O/R Mapping), NAspect (AOP), NFactory (Dependency Injection) and NPath (in memory object querying).

Mats Helander's Weblog - http://www.matshelander.com/wordpress
Puzzle.NET - http://www.puzzleframework.com
Avanade Netherlands - http://www.avanade.com/nl/

References

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

[Fowler AnemicDomainModel]
Fowler, Martin. http://martinfowler.com/bliki/AnemicDomainModel.html

[Fowler PoEAA]http://martinfowler.com/bliki/AnemicDomainModel.html Fowler, Martin. Patterns of Enterprise Application Architecture. Boston, MA: Addison-Wesley, 2003.

[GoF Design Patterns]
Gamma, Erich, Richard Helm, Ralph Johnson, and John M. Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software. Reading, MA: Addison-Wesley, 1995.

[Helander DMM]
Helander, Mats. http://www.matshelander.com/wordpress/?p=30

[Helander Obese Domain Model]
Helander, Mats. http://www.matshelander.com/wordpress/?p=75

[Nilsson ADDDP]
Nilsson, Jimmy. Applying Domain-Driven Design and Patterns. Addison-Wesley, 2006.


You can find the source code here.

Rate this Article

Adoption
Style

BT