C# – Do not declare interfaces for immutable objects

cimmutability

Do not declare interfaces for immutable objects

[EDIT] Where the objects in question represent Data Transfer Objects (DTOs) or Plain Old Data (PODs)

Is that a reasonable guideline?

Up to now, I've often created interfaces for sealed classes that are immutable (data cannot be changed). I've tried to be careful myself to not use the interface anywhere where I care about immutability.

Unfortunately, the interface begins to pervade the code (and it's not just my code I'm worried about). You wind up being passed an interface, and then wanting to pass it to some code that really wants to assume that the thing being passed to it is immutable.

Because of this problem, I'm considering never declaring interfaces for immutable objects.

This might have ramifications with respect to Unit Testing, but other than that, does this seem a reasonable guideline?

Or is there another pattern I should be using to avoid the "spreading-interface" problem I'm seeing?

(I'm using these immutable objects for several reasons: Mainly for thread safety since I write a lot of multi-threaded code; but also because it means I can avoid making defensive copies of objects passed to methods. Code becomes a lot simpler in many cases when you know something is immutable – which you don't if you've been handed an interface. In fact, often you can't even make a defensive copy of an object referenced via an interface if it doesn't provide a clone operation or any way of serialising it…)

[EDIT]

To provide a lot more context for my reasons for wanting to make objects immutable, see this blog post from Eric Lippert:

http://blogs.msdn.com/b/ericlippert/archive/tags/immutability/

I should also point out that I'm working with some lower-level concepts here, such as items that are being manipulated/passed around in multi-threaded job queues. These are essentially DTOs.

Also Joshua Bloch recommends the use of immutable objects in his book Effective Java.


Follow Up

Thanks for the feedback, all. I've decided to go ahead and use this guideline for DTOs and their ilk. It's working well so far, but it's only been a week… Still, it's looking good.

There are some other issues relating to this that I want to ask about; notably something I'm calling "Deep or Shallow Immutability" (nomenclature I stole from Deep and Shallow cloning) – but that's a question for another time.

Best Answer

In my opinion, your rule is a good one (or at least it's not a bad one), but only because of the situation you are describing. I wouldn't say that I agree with it in all situations, so, from the standpoint of my inner pedant, I'd have to say your rule is technically too broad.

Typically you wouldn't define immutable objects unless they are essentially being used as data transfer objects (DTO), which means that they contain data properties but very little logic and no dependencies. If that is the case, as it seems it is here, I'd say you are safe to use the concrete types directly rather than interfaces.

I'm sure there will be some unit-testing purists who will disagree, but in my opinion, DTO classes can be safely excluded from unit-testing and dependency-injection requirements. There is no need to use a factory to create a DTO, since it has no dependencies. If everything creates the DTOs directly as needed, then there's really no way to inject a different type anyway, so there's no need for an interface. And since they contain no logic, there's nothing to unit-test. Even if they do contain some logic, as long as they have no dependencies, then it should be trivial to unit-test the logic, if necessary.

As such, I think that making a rule that all DTO classes shall not implement an interface, while potentially unnecessary, is not going to hurt your software design. Since you have this requirement that the data needs to be immutable, and you cannot enforce that via an interface, then I would say it's totally legitimate to establish that rule as a coding standard.

The larger issue, though, is the need to strictly enforce a clean DTO layer. As long as your interface-less immutable classes only exist in the DTO layer, and your DTO layer remains free of logic and dependencies, then you will be safe. If you start mixing your layers, though, and you have interface-less classes that double as business layer classes, then I think you will start to run into much trouble.

Related Topic