Here at Salesforce, a lot of our code is written in object oriented programming (OOP) languages, particularly Java. Java is very flexible; in large projects, what makes it work (or not work) comes down to your use of conventions: common patterns and rules of thumb that simplify your program and help other engineers understand it more easily.
Recently I wrote and deployed some code that uses a convention called value objects. Since not everyone is familiar with this simple, yet powerful OOP concept, I decided to write this brief summary of what they are and why you should use them.
To understand what value objects are, let’s first look at what they are not.
Most objects in modern applications represent things with an explicit identity. Let’s say you’re working with an email application, and you have records stored in a database for the messages you’re composing and sending. A user can create more than one “identical” email message (that is, with the same subject and body), save them, and send them. But your application would have to consider these to be two separate entities; they’d have different identities, represented by unique IDs. Even though their composition is exactly the same, the two objects are still viewed as unique under our domain model; they’re not equal because they have different IDs. These IDs represent no descriptive information about the objects they are tied to; their only purpose is to show that they’re different. An object whose equality is determined by its identity (commonly expressed through an artificial identifier), is not a value object.
Conversely, an entity whose equality is wholly determined by the information it contains is a value object. Think of the concept of a book, from the literary point of view. How do you distinguish each individual work? Usually that’s done by evaluating three pieces of information: the author, the title, and the contents. So if you’re reading “The Cherry Orchard” by Anton Chekhov, you only need to obtain one copy, and it doesn’t matter which copy you get; they’re all interchangeable, because the object you care about is defined through its value (author, title, contents). The physical manifestation–whether that’s a hardback copy, a paperback, a photocopy, a PDF, etc.–doesn’t matter.
Another common example of value objects is money. Think of an item in an online shop; its price usually has two components: the amount (usually represented by a floating point integer, like 13.37) and the currency type, usually represented by a string (e.g. “$” or “RUB”). Since currency isn’t a built-in type in the language, it makes sense to represent this with an object. But, just like you’d never create a database with a record for every possible price / currency combination, it doesn’t make any sense to try to impose an artificial identity upon these objects through an ID or some similar construct. The money object is defined solely by the values it’s composed of; “13.37 US$” is “13.37 US$” no matter what it applies to.
Taking it one step further: in the real world, money is interchangeable. To a consumer, one $50 bill is no different in value from another $50 bill. In your application, this means the price for Product A and the price for Product B can be represented by the same money value object, if they both cost the same amount. This points to another fact about value objects: they are immutable. That is, you can’t alter the values in a value object after it has been constructed. If you need different values, you construct a new object. Immutability gives your program a lot of benefits, because when something is immutable, it’s simpler to reason about. (Don’t believe me? Read Effective Java by Joshua Bloch for a more in-depth explanation.)
In practice, there are several ways to construct value objects. You can always do it using the new operator, if you know what values you need. Alternately, you can construct it by calling a method of an existing value object, if the new values depend on the old ones. In that case, the original value object should still remain unchanged (remember, it’s immutable!). You should employ the “ask, don’t tell” principle: ask an existing object to create a new one for you and let it handle all the required logic, instead of reaching into the object, pulling out specific pieces of information, and using them to create your own object.
The line between a VO and an identity object often depends on your perspective. In my previous example, it made sense to represent books with a value object, because a reader doesn’t care which copy they have. However, if you’re a library, each individual book suddenly needs an identity, because you’re interested in each physical copy of the book, since you have several and need to track the status of each one (has it been checked out? which shelf is it on? what condition is it in?).
Value objects are very powerful object oriented programming constructs, and can improve your code greatly if used properly.
Still fuzzy about the purpose of VOs or their difference from identity objects? Check out this great podcast by Mathias Verraes and Konstantin Kudryashov.
Want to take a deeper dive into VO theory? Check out this wikipedia page.
And remember these four main properties of value objects: