re-motion Team Blog

From the Team

Mixins in Domain Design

with 6 comments

Ayende Rahien started a nice thread via his blog entry Aspects of Domain Design. He shows how a rule could be implemented as an aspect (in the AOP sense) that modifies a method. That was an invitation to discussions about whether this should really be done via aspects, and the invitation was well received.

In the comments, I remarked that this sounds much more like multi-dimensional separation of concerns to me. After all, AOP as a paradigm focuses on cross-cutting concerns (like “logging, transactions, security, and caching” – Ayende), but not quite as much on individual types and their semantics.

The notion of multi-dimensional SoC seems to be buried quite deep in the common wisdom of our profession, although there are quite nice implementations, and people can often see the advantages. Still, its status is that of alchemy, only less known. Some people use AOP frameworks or languages for multi-dimensional SoC, and technically, dedicated frameworks for multi-dimensional SoC have a lot in common with AOP frameworks. But personally, I would not like to do much of either using a toolkit made for the other (read more here).

Either way, it’s quite hard to find guidance about how to use any technique for the goal of multi-dimensional SoC. (Ivar Jacobson’s Aspect-Oriented Software Development with Use Cases being a rare exception.) So I thought I’d just start writing about some of our experiences at rubicon with our own mixin implementation.

I always believed that dynamic rule mechanisms should be made explicit where they are to be expected. We created our mixin mechanism to enable 3rd parties to create arbitrary extensions and modifications (notwithstanding the “virtual”-requirement) without modifying our source code or waiting for explicit extension points.

Of course, in a large enough development organization, you have to treat other teams as 3rd parties too, because it becomes just unmanageable to create extension points whenever anybody needs them. For the requesting party that would be pretty tough too, because they would have to live off the trunk and wait for every modification to be designed, implemented, tested and delivered before they can start working.

Using mixins proved to be a panacea for many of those problems. At the beginning, there were several reservations about overusing them, and in fact I’m still not sure how happy I am with the hundreds of mixins that emerged in some projects. But I did eventually give in to the notion that in some cases, explicit extension points would make the system just more fragmented and ad-hoc than using one well-understood paradigm for all of them. It’s still something that needs to be decided on a case-by-case basis, and I’m not sure if Ayende’s example (Account.Withdraw) is a very good one to make that point, at least not without any context.

There’s another example I like for using mixins: parallel class hierarchies.

Here’s the problem: I have an OO domain and a generic UI layer that uses data-binding on steroids. This UI can display icons for objects, but of course it cannot go ask the domain objects. We don’t want UI code in our domain classes after all.

So we have an icon service that the UI can ask for icons. Pseudo code:

interface IIconService 
{
  string GetIcon (DomainObject obj); 
} 

Now most domain objects just return classname.gif, so this service is easy to implement. But wait, here’s a special rule:

Male and female persons use different icons.

Now we could have an if-statement in GetIcon, but that’s not very OOP. How do we use polymorphism without tainting the domain?

We need another class tree, somehow attached to the original one.

Here’s how this is done using mixins:

namespace Domain 
{
  class DomainObject { } // layer super type
  class Person : DomainObject { }
} 

namespace UI 
{
  public interface IDomainObjectMixin 
  {
    string GetIcon ();
  } 

  [Extends(typeof(DomainObject))]
  class DomainObjectMixin<TDomainObject> : Mixin<TDomainObject>, IDomainObjectMixin
    where TDomainObject : DomainObject
  {
    virtual string GetIcon ()  
    {
      return This.GetType().Name + "gif";
    }
  } 

  [Extends(typeof(Person))]
  class PersonMixin<TPerson> : DomainObjectMixin<TPerson>
    where TPerson: Person
  {
    override string GetIcon() 
    {
      return (This.Gender == Gender.Male) ? "male.gif" : "female.gif";
    }
  }
}

Now you can cast any DomainObject to IDomainObjectMixin and ask for its icon. The PersonMixin class polymorphically provides its own implementation, while all other types derive the implementation of DomainObjectMixin.

class MyIconService : IIconService
{
  public string GetIcon (DomainObject obj)
  {
    return ((IDomainObjectMixin)obj).GetIcon();
  }
}

I think this leads to a nice separation of layers. Sure, you have to grasp mixins, but you need to understand this concept once, as opposed to understanding a variety of ad hoc solutions. (The use of generics and where-clauses in parallel class hierarchies is a bit ugly, but it follows a simple rule that you can just learn if you don’t want to dig deep and understand why it’s required.) Kind of reminds me of Greenspun’s Tenth Rule, except that a more obvious conclusion from that rule would be to use another language, I guess, but a well-designed framework is still much better than “an ad hoc, informally-specified, bug-ridden, slow implementation” in each project.

There’s another argument I hear a lot that I’d like to address. It goes like this: In OOP, composition is usually preferable to subclassing. That’s not quite true. Subclassing is a very convenient way of gaining a certain set of features (like polymorphism and implementation inheritance), and it would be more than a bit tiresome to do OOP without it. But the more complex a problem gets, the less likely it is that we can solve it just by subclassing. For many problems, single inheritance just won’t do, and multiple inheritance brings its own set of problems. But let me get this straight: yes, we’re trying to make mixins as simple to use as subclassing, so they are easier to learn, and you can apply some of your valuable OOP experience. But the implementation of mixins is basically composition. (There is some sub class generation, but hey, somewhere the composition gluing has to be done.) So the bottom line is, mixins are just classes with a set of composition and delegation rules attached to them. That’s a weird way of thinking about mixins, but the most correct one if you’re reasoning about them in the context of the inheritance vs. composition debate.

– Stefan

Edit: missing reference for Account.Withdraw

Edit: replaced Type Of (T) notation by Type<T> (Left over from an attempt to post this sample to a blog that thinks <T> is an HTML tag.)

Written by Stefan Wenig

November 25th, 2008 at 3:46 pm

Posted in mixins

6 Responses to 'Mixins in Domain Design'

Subscribe to comments with RSS

  1. I have been following this for a while, when can we expect a OSS release, is the preview stable enough for development? Do you have more documentation/examples to help new-comers like me get started.
    Thanks for the effort
    Job Samuel

    Job Samuel

    27 Nov 08 at 05:15

  2. Job,

    you can expect a full release within a few days. The SVN repository is up and running, It’s just a matter of me getting to work out how and where to put the legalese, which has been postponed a few times since my first post due to more urgent (not important) matters, but pressure has been building up from partners in the last few weeks. (Asking here helps to put it up on my list too, just in case other people are watching this and wondering why nothing happens. Please tell us you’re there!)

    The license will be LGPL. What you can download right now should be enough to start development (most major changes since then were in other parts of the framework, mixins are pretty stable).

    You can expect the ObjectFactory syntax to change from
    ObjectFactory.Create<Type>().With (arg1, arg2);
    to something _like_ this:
    ObjectFactory.Create<Type>(TypedList.Create(arg1, arg2));
    or for no arguments, just
    ObjectFactory.Create<Type>();

    There are some minor modifications too, but you’re unlikely to run into them when you’re just starting. We will publish an update when this is done.

    We’re making good progress with documentation, but again, we started with other parts of the framework. I think you can get quite far with the information on this blog. If that’s not enough, please just ask.

    – Stefan

    Stefan Wenig

    27 Nov 08 at 10:17

  3. Job,

    you can expect a full release within a few days. The SVN repository is up and running, It’s just a matter of me getting to work out how and where to put the legalese, which has been postponed a few times since my first post due to more urgent (not important) matters, but pressure has been building up from partners in the last few weeks. (Asking here helps to put it up on my list too, just in case other people are watching this and wondering why nothing happens. Please tell us you’re there!)

    The license will be LGPL. What you can download right now should be enough to start development (most major changes since then were in other parts of the framework, mixins are pretty stable).

    You can expect the ObjectFactory syntax to change from
    ObjectFactory.Create<Type>().With (arg1, arg2);
    to something _like_ this:
    ObjectFactory.Create<Type>(TypedList.Create(arg1, arg2));
    or for no arguments, just
    ObjectFactory.Create<Type>();

    There are some minor modifications too, but you’re unlikely to run into them when you’re just starting. We will publish an update when this is done.

    We’re making good progress with documentation, but again, we started with other parts of the framework. I think you can get quite far with the information on this blog. If that’s not enough, please just ask.

    – Stefan

    Stefan Wenig

    27 Nov 08 at 10:18

  4. Sorry to bug you again. I am waiting to see some documentation and test cases.

    Thanks
    Job Samuel

    Job Samuel

    9 Dec 08 at 04:35

  5. Just to let you know we didn’t forget about it. I tried to get it done over the weekend, but other stuff turned up and guess what, it turns out to be quite a piece of work to get different licensing information applied correctly to a code base consisting of > 50 individual C# projects and assemblies…

    A few more days.

    Stefan Wenig

    15 Dec 08 at 08:23

  6. Thanks, will wait.

    Job Samuel

    18 Dec 08 at 05:11

Leave a Reply