27

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.

Mark Rogers
  • 96,497
  • 18
  • 85
  • 138
  • AFAIK Rhino Mocks cannot mock concrete class methods unless they are overrideable. Thus you would have to make all domain object methods virtual. Not good. – Klas Mellbourn Jan 22 '10 at 08:23
  • Related: http://stackoverflow.com/questions/2659366/java-interfaces-methodology-should-every-class-implement-an-interface – jaco0646 Aug 09 '16 at 22:32

6 Answers6

9

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?

Paul Sonier
  • 38,903
  • 3
  • 77
  • 117
  • 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 May 05 '09 at 17:15
  • 1
    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. – Paul Sonier May 05 '09 at 17:21
  • 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? – Paul Sonier May 05 '09 at 17:25
  • 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 May 05 '09 at 17:27
  • 3
    I just think that they have misunderstood what decoupling means, and why you should do it. – Mark Rogers May 05 '09 at 17:31
7

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
  • 110,348
  • 25
  • 193
  • 263
  • 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 May 05 '09 at 17:38
  • +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 May 05 '09 at 17:40
  • If you already know the answer, why are you asking the question? – Charlie Martin May 05 '09 at 17:47
  • 2
    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 May 05 '09 at 18:40
  • 1
    I would like to upvote this answer more than once. I've had to walk into a project "two years later" after working with properly written code elsewhere. My productivity has plummeted. – jeremyjjbrown Feb 05 '14 at 17:27
5

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
  • 2,553
  • 1
  • 22
  • 22
4

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

James Gregory put it better than me here.

Mark Rogers
  • 96,497
  • 18
  • 85
  • 138
  • Of course Anemic Domain is the real issue. But that about when you already have one. You can at least create an insulator between the depender and the implementation so you can change with fewer headaches. – jeremyjjbrown Feb 05 '14 at 17:31
1

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.

Memo
  • 329
  • 3
  • 5
0

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.

Anthony Johnston
  • 9,405
  • 4
  • 46
  • 57
  • Surely, you would need to use generics, not interfaces, in order to abstract the difference in type for the object id, unless the key itself was modelled on the weakest type (e.g. string). – StuartLC Aug 08 '16 at 09:15
  • I use a string every time now, gets way too complicated if you use generics, you have to tell your services about the generic in the model your passing, and if it has a sub property which is a generic entity and the service is generic - you get my dift – Anthony Johnston Aug 10 '16 at 15:06