UPDATE: With improvement in my ideas, experience and knowledge, I no longer agree with having an interface for a Value Object. I don’t write interface for Value Objects anymore. The most solid reason for this is given by Kent Beck. He writes:
Paradox: by not considering the future of your code, you make your code much more likely to be adaptable in the future.Test-driven Development by Example by Kent Beck
Code for tomorrow, design for today.Test-driven Development by Example by Kent Beck
With that being said, if you want to read the rest the of article and my previous thoughts, be my guest.
Among the different reasons behind having an interface is decoupling – that is the Inversion of Control. According to Uncle Bob’s DIP, the dependency-inversion principle:
a. High-level modules should not depend on low-level modules. Both should depend on abstraction.
b. Abstraction should not depend on details. Details should depend on abstraction.
You are probably aware of this in other cases. But why should there be an interface for a Value Object?
According to Martin Fowler, one of the purposes of a Value Object is also to be a place to accomodate any functionality related to that object in future. This indicates a growing object and an interface becomes important as object grows.
You may not want to add the interface at the introduction of a Value Object due to YAGNI. However, I think it is a right time to introduce the interface as soon as the Value Object start to contain public methods.
Another case where introducing interface at the introduction of Value Object can be very useful is, when the Value Object has to travel through multiple levels of abstractions.
I started a web project recently by having interfaces for all Value Objects. Later, I thought to remove those interfaces. The very first interface I was to remove was “SimpleHttpResopnse”. It contained http status code and content. This was actually the response generated by controller, which in turn, used a long abstraction of classes.
Controller >> UseCase >> Responder >> Factory
All had return type “SimpleHttpResopnse”. If it is not an interface, this would be a big refactoring in future if “SimpleHttpResopnse” grows into something big. I don’t think having an interface hurts here.