18

I am creating the domain model in my system. When designing my model objects, should I make interfaces for each entity object? People have told me that our web tier should not care about the implementation of an entity and we should be able to swap out implementations, but I'm not sure that would ever happen.

For example, if we have a Teacher class that maintains a List of Students, the getStudents method could either be:

public List<Student> getStudents() {
      return this.students;
}

or this:

public List<Student> getStudents() { 
     return someExternalService.retrieveStudents();
}

I understand this benefit, but what is the general practice?

skaffman
  • 398,947
  • 96
  • 818
  • 769
sma
  • 9,449
  • 8
  • 51
  • 80
  • 1
    "general practice" isn't necessarily the same as "good practice", especially when it comes to OO design :) – skaffman Mar 09 '10 at 22:43
  • 5
    I don't get your example. Is your question whether Teacher should implement some interface, or use a dependency through an interface? I have different answers for these two cases. Your text makes me think you're thinking the former, but the example makes me think you want the latter. What is it? – R. Martinho Fernandes Mar 09 '10 at 22:46
  • Martinho, my question is whether Teacher should implement an interface and have resultant TeacherImpl classes. – sma Mar 09 '10 at 23:00
  • 3
    but your example seems to be asking "should Teacher hold data or just invoke other classes?" – matt b Mar 10 '10 at 00:48

6 Answers6

15

Unless you have good reason to think you will need to swap-out the model I wouldn't worry about it yet. Based on the YAGNI principle (You ain't gonna need it)

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
David
  • 1,940
  • 3
  • 17
  • 30
  • Thanks for the answer. I agree with both. I actually have a follow-up to this that I'll post as a separate question. It involves modelling associations. – sma Mar 09 '10 at 23:06
  • 5
    In my opinion, YAGNI applies more to functionality, than design. Interfaces don't contribute to code bloat or complications in testing, for example; in my experience, it's the absence of interfaces for the sake of expediency that's the problem. – Noel Ang Mar 09 '10 at 23:21
  • @Noel - I think you're right about it's origins but I think it can be a useful to avoid over-engineering. I have found a couple of occasions to say to someone "You ain't gonna need that" and they can either refute your claim and make a good argument for the addition, or they find they can't justify it and decide/realise it's not really a requirement. I agree in this case there's no great harm in adding interfaces but it could lead to more code being added "just in case". – David Mar 09 '10 at 23:37
  • In full agreement with Noel, using this interface is more KISS than !YAGNI. – orbfish Nov 03 '11 at 20:51
  • 1
    If you intend to put logic or behavior in your domain model, then you may want an interface. If you don't, whenever something uses that behavior, you will have to state test the outcome rather than just test that the method was called. – DanCaveman May 27 '15 at 14:41
  • 1
    This is an awesome answer... I used to create interfaces for everything without any consideration of whether it was required right now. It was only one day a junior developer questioned why I was doing it, insisted that I was wrong and that I should think about whether I really need it right now. Unnessisary polymorphism reduces code simplicity. Daniel was right, he went on to teach me a few valuable lessons. – K-Dawg Jan 02 '19 at 10:05
  • Using an interface for a model is annoying when you have `SomeMethod(IModel model){}` and you only have one class implementing `IModel`. You can't see what class is actually used unless you do Ctrl+F12 on the IModel to see the implementation. – David Klempfner May 07 '21 at 02:47
3

None of the projects I've ever seen or participated in had interfaces for domain entities.

But in one of my projects I had interface NamedEntity:

public interface NamedEntity {
   int getId ();
   String getName ();
}

All domain entities implemented this interface. It gave me a possibility not to create different jsf converters for different entities but create one converter which used this interface instead of concrete domain classes.

Roman
  • 64,384
  • 92
  • 238
  • 332
  • 1
    Nice example. Nitpick: you say none of the projects you've seen or participated had that phenomenon, and then you quickly provide an example of one... – R. Martinho Fernandes Mar 09 '10 at 22:56
  • This upvote revealed bug (or simply unclear behavior) in SO reputation counting. – Roman Mar 09 '10 at 22:59
  • I agree. I really don't want any to have an interface but others are disagreeing. – sma Mar 09 '10 at 23:01
  • @Roman: there's a reputation cap of 200/day based on upvotes. Only bounties and accepted answers will be added hereafter. Also see the faq and meta. – BalusC Mar 09 '10 at 23:16
  • @BalusC: see this post http://meta.stackexchange.com/questions/41683/bug-of-hidden-feature-in-reputation-counting After some thought I think it's not a but. – Roman Mar 09 '10 at 23:27
  • Oh, you're already aware of the cap :) Yes, look like some sort of bug. Maybe related to the fact that you accepted an answer after the cap hit. – BalusC Mar 09 '10 at 23:33
2

I can't speak to general practice, but it is hardly just about hiding the implementation.

It's about formalizing the interface as the basis for documentation and contracts.

In abstracting your models out into interfaces, you are creating documentation for service client developers. Depending on your development style, you may or may not already have a formal description of your service (e.g., a WSDL-based description). Interfaces can fill that need.

Noel Ang
  • 4,989
  • 1
  • 25
  • 19
  • 1
    Actually that somewhat applies to my situation. There are service client developers basing services off of my model objects, so maybe the interface approach isn't a bad thing. – sma Mar 09 '10 at 23:18
2

I think there is an important difference between having interface for service to retrieve the object and the model object itself.

At runtime the service to load a model object can differ based on from where you are requesting the data. But the format and type of data object expected does not change, no matter how you create this object. Therefore model objects which carry the state would not need an interface, but service classes to create and load these model objects needs the interface.

The only reason for model objects to have interfaces would make sense if model object is not just a simple bean type of object but object which exposes some kind of behavior as well.

Fazal
  • 2,991
  • 7
  • 29
  • 37
0

My general view is that I would not create a one-to-one set of interfaces for the domain models, since this does nothing other than duplicate your domain model's class structure. It doesn't add anything useful.

The two cases I can think of immediately where I would consider introducing interfaces is:

  1. an interface describes the contract/behaviour of some set of classes in the domain model, where it is useful to model that behaviour independantly of the classes which implement it
  2. you need to expose your domain model to external clients and want to hide implementation details from them

In other words, add interfaces if they help you describe behaviour or help you hide implementation details from clients. Other reasons might be valid, but those are two that come to mind.

KarstenF
  • 5,345
  • 3
  • 21
  • 16
  • Yeah, I completely agree. This actually started out as number 2 where we were exposing the domain model to external clients. That approach has since shifted and now I'm stuck with an interface for every model object. I considered getting rid of it, but wanted to check with the community first. – sma Mar 11 '10 at 02:56
0

Extracting an interface is one of the simplest refactorings; worst case it is a class re-name -> move method. The effort to change your mind, once you've found a reason to do so, is minimal. I have always found that if a decision is easy to change, it reinforces YAGNI and KISS even more. The counter-argument is that it is not much effort to create an interface initially, which is true, but the maintenance adds up over time if the decision is made many times over - often not being used.

walnutmon
  • 5,873
  • 7
  • 42
  • 57