Value Objects

Since I’ve already set you up in a DDD mood with the previous post, let’s capitalize on that further. In this post, I’ll try to provide an easy explanation of Value Objects and their benefits.

Motivation

Most of the concepts we’re modeling in our software have no global identity. If you wonder what I meant with the previous sentence, look inside your entity classes. Each of them contains a bunch of fields, usually represented by standard types such as String or  BigDecimal, or by simple data structures. These, without the context of the enclosing entity, cannot be distinguished from other Strings, BigDecimals or structures. We don’t identify them by ID of any kind; we identify them only by their values.

For example, if we were talking about a Person class, we would probably see fields like firstName, lastName, or address. A person has a clear, global identity. If there was an object representing me, the object would refer to a real guy sitting at work, finishing a blog post and waiting to go home – I’m an entity. On the other hand, if we were talking only about a String like “Grzegorz”, we don’t have this global scope – it’s just a value.

Values like the ones mentioned above can have certain logic associated with them e.g. validation, transformations or calculus. As we’re using an OO language, it makes all the sense in the world to use its powers and combine the value and the logic together in an object.

Value Objects

Value Objects pattern does just that – transform our values into objects. Everything boils down to wrapping the standard types inside our own, named by the concept their representing:

As the value objects have no identity, we compare them together by simply comparing all the values they contain:

Usually, we also make/treat the value objects as immutable i.e. instead of changing the value objects, we create new instances that wrap the new values:

There are practical and conceptual reasons behind this. From the practical perspective, immutable types are handy, as they can be easily shared between different objects and returned by the entities without risk of compromising consistency. From the conceptual perspective, it makes sense to create a new instance of a value object when the value changes, as we’re literally assigning a new value.

Benefits

For a person unfamiliar with the concept, this might look like heavy overengineering. In reality, value objects have some nice advantages:

  • the code gets more expressive:
  • they make our code safer, as the type system prevents us from doing stupid mistakes:
  • they give us flexibility in terms of internal representation e.g. I could easily change:
    to:
    without changing most of the PersonId clients.
  • as already said, they also encapsulate related logic e.g. validation:
    or calculus:

Drawbacks

The obvious drawbacks of value objects are that the numbers of classes in the project might grow significantly and, as they’re usually immutable, the number of created objects too. While I wouldn’t initially care about the performance, as in most cases it would not be a bottleneck, I’d be extremely careful not to overdo the concept and bloat the project with a ton of String wrappers that do nothing but wrapping. In my projects, I create value objects only when I see that there is a piece of logic to encapsulate.

Implementing Value Objects

All the examples I’ve shown by now were in pseudo-Java as their purpose was to convey the idea rather than show all the guts. Now we’ll look at three real implementation examples for value objects – using plain Java, Project Lombok, and JPA.

Plain Java

If we’re not using libraries like Lombok or Immutables, and we don’t use JPA for persistence, we can implement value objects in plain Java. Basically, this boils down to implementing an immutable class by ourselves and providing an equals method that compares fields by values. As a reminder, to create such an immutable class, we have to:

  • make it final
  • make all the fields final (this also implies no field mutation in methods and creating new objects when someone wants a value object with different data)
  • copy all mutable state during construction and retrieval

Project Lombok

Many of us use plugins like Project Lombok or Immutables to limit the amount of boilerplate code we need to write. The former has a @Value annotation designed specifically to support easy creation of value objects – it auto-generates private and final keywords, a constructor, getters, and equals/ hashcode methods. It’s important to know that it does not support defensive-copying, which may force us to use different types than we’d normally do. In our example, we have to use Instant instead of Date.

JPA

It’s common that developers store their value objects in a relational database using JPA. In such a case, we need to relax the immutability constraints and add some annotations. Since the implementation can’t make the fields final, we have to be more careful about people not adding setter methods to the value objects.

Summary

Value Objects pattern transforms values in our projects into real objects, giving us more type safety, hiding implementation and giving home to all related logic. That being said, we should always evaluate if mentioned benefits outweigh the drawbacks of creating extra classes which, in Java, implies extra source files and a rapidly growing size of the project. To implement a value object, we simply wrap a value into an immutable class with an equals/hashcode pair that compares the objects by values.

About the Author Grzegorz Ziemoński

King of Tidy Java, nerd that thinks about producing perfect software all the time and proud owner of 2 cats.

follow me on:
  • cblin

    A great article about VO, thanks !

    I think you should mention other important drawbacks of VO :
    * serialization is horrible (ex : JSON or XML like person.id.value, person.lastname.value, etc…) except if you add method toJson or toXml to every object which is fastidious,
    * simple manipulations require a dedicated method (ex : Money.isGreater, Mony.IsGreaterOrEquals, …) which often result in code like person.lastname.toString().StartsWith(“xxx”) or int.fromValue(person.age.toString()) > 18 which are more horrible than everything else in the world,
    * validation is redundant with attributes (ex JSR303) and it is difficult to have multiple errors in the same roundtrip,
    * etc…

    This is why I never use value object that just wraps a primitive value.

    However, I deeply use value objects as input/output of my APIs.

    For example, I will not have
    bool ScanArticle(string code)
    but I will have
    ScanResult ScanArticle(ScannedInput input) with ScanResult that wraps the bool and ScannedInput that wraps the string

    This to guarantee that my APIs are easily callable even if I add some “arguments” to the method or some “results”.
    In the example, ScanResult could wrap the boolean for the moment but I bet there will be quickly a reason field.

    This was my 2 cents,

  • Developer Dude

    For simple value objects I use immutable classes with final public vars, a builder and private constructors (one no arg, one copy).

    No setters/getters. Just the builder, toString, equals and hashcode (the latter three using Apache commons lang).

    The main idea is to have an ‘immutable’ (I know they are not perfectly immutable, but they are simple and discourage mutation – i.e., a dev has to ‘defeat’ the immutability on purpose). This seems to work well for transferring values between a client and the datastore via services.

    To address serialization, we use JaxB annotations and Spring service endpoints/etc. – not clean, but it works. I have found that serialization in many projects can depend on context; on the server side the values may need to be XML or JSON, on the client side the values may need to be exported to an Excel spreadsheet. Building all of this into a value class pollutes it more than I care to, and doesn’t handle the cases where different values need to be serialized together.

    We do create new value objects when we need to mutate, and this is not that often for most of the classes (one particular value class is created in the hundreds, the rest are usually singular or less than a dozen, and created/mutated singly – e.g., customer, address, etc.) and with the builder it is simple (pass the original to the builder, then call the method(s) to mutate then call the build() method.