views:

394

answers:

5

One thing I see in some DDD enterprise apps that I work on, is the use of interfaces that are identical to the domain entities, with a one-to-one mapping of properties and functions. Indeed a domain object is always used through it's one-to-one interface, and all domain entities have a one-to-one interface in this style.

For example:

Domain object Account:

public class Account : IAccount
{
     public string Name {get;set;}
     //...some more fields that are also in IAccount
     public decimal Balance {get;set;}
}

And it's matching interface

public interface IAccount
{
   string Name {get;set;}
   //... all the fields in Account
   decimal Balance {get;set;}
}

But lately I've become increasingly convinced that this is, in fact, an anti-pattern.
I ran it by some architects in the open source community, and they say that this is based on design mistakes or flaws, somewhere up the chain of design.

So I tell my colleagues that they should quit creating interfaces for the Domain objects. Because there is no purpose to them, and you have to update the interface whenever you update the domain entities.

First the claim was made that these interfaces provide 'decoupling', but I counter that because the interfaces have a one-to-one relationship with the domain entities that they do not really provide any decoupling, a change to the interface means a change in the domain entity and vice-versa.

The next claim is that we need the interfaces for testing purposes. My counter is that Rhino-mocks provides for the mocking and stubbing of concrete classes. But they claim that Rhino-mocks has trouble with concrete classes. I don't know if I buy that, even if rhino-mocks has trouble with concrete classes, that doesn't necessarily mean we should use interfaces for the domain entities.

So I'm curious:

Why would you have one-to-one interfaces for your domain entities?

Why not?

Why is it a good or bad practice?

Thanks for reading!

EDIT: I should note that I use interfaces all the time, and I believe that if it's called for I will use an interface at the drop of a hat. But I'm specifically referring to domain entities with one-to-one interfaces.

+2  A: 

It's a bad practice as described, but...

There's no specific reason that your interfaces need to be different than your domain entities; sometimes it really is the right mapping. But it's suspicious that it's always the case. The point of concern there is a question of whether or not the interfaces were truly designed, or whether they were just thrown into place out of lack of time / laziness.

To use your example, the IAccount interface you describe exposes getters and setters on the Account object; it seems a little odd and unlikely that everything that uses an Account will have a need to set the balance on the account, and that that implied permission is specified at that level of interface. Is there no place in your system where you want to merely check but not set the Account balance?

McWafflestix
Yes, there are legions of areas where the entire interface is not used. In fact it is more the case that a part of the interface is not used, than is.
Mark Rogers
Yeah, the apps are not domain-driven design then; it's pure data-driven design. And it sounds like it's very poor design, for that.
McWafflestix
I sadly agree...
Mark Rogers
Are these designs / designers specifically averse to composite interfaces? That is, interfaces which compose together the functionality of several underlying domain objects into one coherent interface?
McWafflestix
You mean like a facade or something, no. These interfaces are always exactly like the domain object, even within the domain the interfaces are used instead of the domain objects. The conrete domain objects are only seen when they are newed up.
Mark Rogers
I just think that they have misunderstood what decoupling means, and why you should do it.
Mark Rogers
+5  A: 

The biggest reason for always specifying the domain objects as interfaces instead of directly as classes is to give you a degree of freedom on the implementation. In your example you only have one kind of IAccount, so it's a little redunant.

But what if you had, for example:

public class Account : IAccount { ... }       // Usual account, persistent
public class MockAccount : IAccount { ... }   // Test mock object
public class TransAccount : IAccount { ... }  // Account, not persistent
public class SimAccount : IAccount { ... }    // Account in a performance sim

and so on?

By defining the domain objects as interfaces, you can replace the implementations without disturbing your domain definition.

Charlie Martin
Ergo the sentence that starts "In this example...". But what you'll do to implement the interface is certainly a locus of change, and a desirable property of an OO design is to have "hinge points" at likely loci of change. BTW, I actually used to argue this question the same way you are, and was converted when I wanted to start mocking some stuff for testing.
Charlie Martin
+1 this seems silly until you're two years into maintenance on a monolithic application and you need to implement a change to support new variations without disrupting layers of dependencies. Also, TDD is a no-brainer.
Rex M
If you already know the answer, why are you asking the question?
Charlie Martin
You seem pretty sure. But you still aren't reading what I wrote. IF you have only one kind of IAccount implementor, it's redundant. But in the real world you never do; as soon as you start having more than one -- including wanting a test mock -- it's useful. In a DDD, with factories and repositories, they you use a Template Method and Factory pattern to get some of the same effect, but you still have to deal with unit testing etc. It still comes down to the same point though: IF you have more than one implementation of the same stuff THEN you want an interface.
Charlie Martin
+1  A: 

In general, if my classes are not going to be part of a design pattern like Strategy or Visitor I don't add interfaces.

Adding interfaces is really useful for design patterns like Strategy and Visitor, but in those cases I don't carbon copy the getters and setters of the domain classes. Instead, I create interfaces that are specific for the design pattern interfaces I create.

interface SomeStrategy {
   void doSomething(StrategyData data);
}

interface StrategyData {
   String getProperty1();

   String getProperty2();
}

That allows me to let the domain classes implement those interfaces, or to use the Adaptor pattern. I find this is a much cleaner approach that just creating interfaces for the sake of it.

Design should always reduce uncertainty. Creating interfaces for the sake of it doesn't reduce uncertainty, in fact it probably increases confusion since it doesn't make any sense.

Steven Devijver
Good answer, thx
Mark Rogers
A: 

How do you want to handle data transfer between your business objects down to you data access layer?

Assume we have the following namespaces, Sample.DataAccess and Sample.Business. Then we would have the following.

// in namespace Sample.Business
public class Account : Sample.DataAccess.IAccount
{
     public string Name {get;set;}
     //...some more fields that are also in IAccount
     public decimal Balance {get;set;}
}

// in namespace Sample.DataAccess
public interface IAccount
{
   string Name {get;set;}
   //... all the fields in Account
   decimal Balance {get;set;}
}

How do you handle your business objects in the data access layer without including a reference to Sample.Business (which is bad because your Business objects are already going to have a reference to Sample.DataAccess)

This is what I have seen done.

// in namespace Sample.DataAccess
public class AccountDA
{
   public AccountDA()
   {
   }

   public int SaveAccount(IAccount account)
   {
      //access the elements and set them in their
      //parameters for a stored proc.
      //otherwise handle in your ORM
   }
}
Ty
If you use an IoC container, like structure map, you won't need to have a reference to the data layer in your domain layer.
Mark Rogers
In most of the DDD apps I've seen, it's the duty of the services to talk to the repositories.
Mark Rogers
A: 

One-to-One Interfaces on entities are an anti-pattern

James Gregory put it better than me here.

Mark Rogers