views:

228

answers:

3

Should Domain Entities be exposed as Interfaces or as Plain Objects ?

The User Interface :

public interface IUser
{
    string FirstName { get; set; }
    string LastName { get; set; }
    string Email { get; set; }
    Role Role { get; set; }
}

The User Implementation (Implemented into LinqToSql Data Access Layer) :

public class User : IUser
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public Role Role { get; set; }
}

The User Implementation (Implemented into NHibernate Data Access Layer) :

[NHibernate.Mapping.Attributes.Class]
public class User : IUser
{
    [NHibernate.Mapping.Attributes.Property]
    public string FirstName { get; set; }

    [NHibernate.Mapping.Attributes.Property]
    public string LastName { get; set; }

    [NHibernate.Mapping.Attributes.Property]
    public string Email { get; set; }

    [NHibernate.Mapping.Attributes.Property]
    public Role Role { get; set; }
}

this only illustrate some DAL specific implementations, don't have a better sample at this time.

A: 

Plain objects, unless there's a common interface for an implementation that can change. That's what interfaces are for. Value classes like Money or Address don't fall into that category.

Your example interface has no behavior whatsoever beyond getter/setter. That's not what interfaces are for.

duffymo
I would consider this specific example to be a domain entity, rather than a value object, because it identifies a specific user. But that would depend on usage.
Cylon Cat
Same conclusion for me - domain entity or value object, interfaces allow implementations to change without affecting clients.
duffymo
+2  A: 

Interfaces are normally considered to be "contracts" and would therefore define behavior. The other major use is for mocking, so that you could provide domain entities that were mock-ups instead of coming from a specific data source (and having dependencies on that source).

For a simple data transfer object, I can't see a lot of use for defining interfaces, but I'm willing to be proven wrong. I'd go with simple objects for this.

Cylon Cat
+3  A: 

My feeling on this is that domain objects (not domain entities, as that title implies something to do with a database) should not be interfaces unless you have a very compelling reason to believe that you will need to support multiple implementations at some point in the future.

Consider that the domain model is the human model. The business/service/document is, literally, the domain. Most of us are developing software for a single business or purpose. If the domain model changes, it is because the business rules have changed, and therefore the old domain model is no longer valid - there is no reason to keep the old one around, running alongside the new one.

The debate is obviously not black-and-white. You might be developing software that is heavily customized at multiple client sites. You might really need to implement different sets of business rules at the same time, and simultaneously have a genuine need to fit them into a unified architecture. But, in my experience at least, these cases are the exception rather than the rule, and although I am not generally fond of the term, this might be a case where you should be thinking to yourself, YAGNI.

Data access is a common area where you want better abstractions (persistence ignorance). In your example, you have NHibernate attributes on your model class. But adding persistence attributes makes it no longer a true domain class because it introduces a dependency on NHibernate. NHibernate and Fluent NHibernate support mapping POCOs using an external mapping declaration instead of attributes on the data class, and this tends to be the preferred approach when using ORMs such as NHibernate or EF4, because it breaks the dependency between persistence model and domain model.

If these mapping methods weren't supported, and you had to use attributes, then I might indeed suggest using interfaces instead, but ORMs today are more sophisticated than that, using reflection and dynamic proxies and method interception to do most of the heavy lifting, so you don't need to create your own abstractions here.

Some types of objects that you would want to expose as interfaces are:

  • Repositories, which are responsible for loading/saving domain objects;
  • Plugins/extensions to your program;
  • View/presenter models, so that different UIs can be plugged in;
  • Abstract data types with many implementations (array, list, dictionary, record set, and data table are all sequences AKA IEnumerable);
  • Abstract operations with many possible algorithms (sort, search, compare);
  • Communication models (same operations over TCP/IP, named pipes, RS-232);
  • Anything platform-specific, if you plan to deploy to more than one (Mac/Windows/*nix).

That's by no means a complete list but it should illuminate the basic principle here, which is that the things best-suited to interface abstractions are the things that:

  1. Depend on factors that are likely beyond your control;
  2. Are likely to change in the future; and
  3. Are horizontal features (used in many parts of the app/architecture).

A domain class will be widely used, but does not fit into either of the first two categories; it is not likely to change, and you have almost complete control over the design. Therefore, unless the classes themselves will be taking on indirect dependencies (which is a situation you should try to avoid whenever possible), I would not go through the extra effort of creating an interface for every class in the domain model.

Aaronaught
@Aaronaught : Ok for ORM specific, now assume i'm using FullText Features, i'll use Lucene.NET which use Attributes too. And as far as i know, there is no way to use external attribute mapping like FluentNhibernate do. So what is the best approach in order to keep my domain entities true POCOs ? Maybe Interfaces work in that way ?
Yoann. B
@Yoann. B: I wasn't aware that Lucene.NET used decorator attributes at all; it definitely doesn't require them. If you want to use them, then you have two choices: Either (a) make your domain model dependent on Lucene.NET, which seems like a bad idea (what if you want to use SQL FTS instead? What if a future version of Lucene.NET does support POCOs?), or (b) move your search objects and repositories to a different namespace/assembly and use a tool like AutoMapper to convert them to domain objects. Either way, I don't think that creating interfaces for the objects would help a great deal.
Aaronaught
@Aaronaught : You said Lucene.NET doesn't require attributes ? its about another question i posted (http://stackoverflow.com/questions/2356593/lucene-net-and-poco-entities) but how do you do without using attributes with Lucene.NET ?
Yoann. B
@Aaronaught : I want my business objects true POCO, as you said, if i want in the future to go using SQL FTS instead of Lucene.NET. I don't mostly agree with your 2nd solution using AutoMapper (or something like that), coz if i Entity-Business Object with NHibernate, then with AutoMapper, then AutoMapper one more time to map BO to ViewModels, it's a lot of mapping, and performances will be affected.
Yoann. B
@Yoann. B: You *may* be right, but beware of premature optimization; it's very likely that more than 90% of your program's total execution time will be spent waiting for database queries or other I/O operations. Mapping is very, very cheap. Having said that, I think you'd have a cleaner design if you used NHibernate's POCO mapping to map entities directly to domain model (if possible).
Aaronaught
As for the Lucene.NET question, I looked at it but it's not entirely clear what you mean. If you look at any Lucene.NET tutorial, they don't involve attributes. You might want to update that question with some information on where you read about this, or even how you're using Lucene attributes now (as I said, I wasn't even aware that there was such a thing, but I've only used Lucene a little bit).
Aaronaught
Lucene.NET only don't need mapping attributes, but i'm using NHibernate.Search which is built on top of lucene.net and requires mapping attributes. I'm looking for a Fluent implementation like Fluent NHibernate for Lucene.NET but not founded yet.
Yoann. B
@Yoann. B: That makes sense now; I haven't used NHibernate.Search before but a quick look at the documentation seems to indicate that it is attribute-based. You should update your other question so people know you're talking about NHibernate.Search, maybe someone else has an answer. You could use interfaces here as a substitute for an additional mapping layer if you only want to *retrieve* data - the problems are going to start happening when you want to *store* data, because you can't create an instance of an interface (unlike a pure domain class, which can always be mapped backward).
Aaronaught
@Aaronaught : I can also create an interface and implement a User and an IndexedUser, then my UserRepository will be able to Retrieve User and Store IndexedUser, both implements IUser but only IndexedUser contains mapping, so on saving NHibernate.Search will also be able to be aware of Lucene Mapping contained in IndexedUser class.
Yoann. B
@Aaronaught : In addition to solve the ability to create an instance of an interfance, i can use an EntityFactory combined with my IoC to inject entity dependencies into it. But i think it's not the best approach. I prefer found a better solution to avoid Lucene.NET mapping in my business objects.
Yoann. B