Question

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.

Was it helpful?

Solution

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?

OTHER TIPS

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.

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.

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

James Gregory put it better than me here.

I agree with you. Interfaces should act as a contract, so there is no value from having one-to-one interfaces with domain entities. It may be useful if you would like to abstract a certain behaviour. But, this will work in certain cases.

Why has this one fizzled out?

I find having an interface for a domain object, as Charlie Martin said, allows me to choose my implementation.

A fundamental example is the identifier (object.Id) for an object, this will be different depending on where you store that object and the responsibility for creating it may or may not rest in the implementation of the data later. In SQL Server you might go for an autonumber, but in Azure table storage you might go for a Guid, but you don't want to have to change the business logic of you app because you change where you store your data.

I may or may not choose to have my domain object persisted, or even use it in the presentation layer - it depends on the scope of my app which is best. But adding a set of common domain interfaces in a common layer allows me to write services against them and reuse them again and again.

We would go over the same argument about what should be an address if we hadn't got IAddress, new programmers would be rewriting stuff for credit cards if it weren't for ICreditCard.

The anti-pattern label is a bad use of language, it's an over simplification for describing the worth of solutions to complex and varied tasks.

There is a place for most patterns even the maligned Singleton, which means its not an "anti-pattern", at least as far as the term suggests.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top