Home
About
Contact
Sunday, July 19, 2009

At QCon London 2009, Dan Bergh Johnsson had a talk on the DDD track about how to make use of Value Objects (VO's) (The Power of Value - Power Use of Value Objects in Domain Driven Design (PDF)). In his talk he took a piece of code and refactored it into a better piece of code by using VO's. By doing this Dan showed some really good concepts of using VO's. Even though I knew about the concept of VO's before his talk, he made me realize many new scenarios where they are applicable. And more importantly that it is not limited to DDD.

So what is a VO anyway? Is it related to value type in .NET?

To answer the last question first: The real answer is no, but the way I see it there is a relation. A value type in .NET is everything that is not an object. Typically simple types like int, char, double, but also enums and structs. The relation is that often you find yourself creating VO's where value types was previously used. It is however not limited to value types.

Now to the first question. I first came across VO's after reading Evans DDD book (commonly known as the blue book). In DDD a Value Object is an object without an Id and are usually immutable. In examples of VO's, Address is commonly used, which I don't find particularly useful. I think Address way too often has an Id and people have a hard time relating to that as a Value Object. I find the Amount example I gave in an earlier post to a better example or the one below illustrated as an interface (borrowed from Dan):

public interface IPhoneNumber {
  bool IsValid {get;}
  string Number {get;}
  string AreaCode {get;}
}

How many times have you used the concept of a phone number in your code? Like mobile, fax, fixed etc… How often have you kept it as a string? How much code do you have for doing different types of validation, getting area code etc? Do you have it all in one place or scattered around in different places? Other examples are Money, ZipCode etc… These are great candidates for Value Objects.

Now that we know what Value Objects are, what is so powerful about them and why should I use them more? Great question :-) Below is my three reasons:

  1. Code readability - I find that using Value Objects greatly improve the overall code readability and eliminates comments. Just like good names on methods and properties does.
  2. DRY (Don't Repeat Yourself) - By having a Value Object for PhoneNumber, you avoid writing code to handle specific cases around phone numbers and you reuse them wherever the concept of a phone number is used.
  3. Helps people getting back into OO thinking – We who have been living in the Microsoft .NET world for a long time have been thought to think of programming from a data/database perspective and not object oriented programming as we once learned it. In other words: think of behavior instead of data.

When I started to use VO's, I soon discovered I used them all over. They really add great value to my code. As an example, lets implement the IPhoneNumber above:

public class PhoneNumber : IPhoneNumber
{
    private readonly string _phoneNumber;
    public PhoneNumber(string phoneNumber)
    {
        _phoneNumber = phoneNumber;
    }
    public bool IsValid
    {
        get { return Regex.IsMatch(_phoneNumber, @"^[01]?[- .]?(\([2-9]\d{2}\)|[2-9]\d{2})[- .]?\d{3}[- .]?\d{4}$"); }
    }
    public string Number
    {
        get { return _phoneNumber; }
    }
    public string AreaCode
    {
        get
        {
            return Regex.Match(_phoneNumber, @"^[01]?[- .]?(\([2-9]\d{2}\)|[2-9]\d{2})").ToString();
        }
    }
}

The above code handles US phone numbers. To be used in a production system there should probably be even more validation in the regexp's, but I hope the example gives you and idea of what I'm thinking.

.Net | Architecture | CSharp | DDD | Patterns
Sunday, July 19, 2009 3:33:57 PM (W. Europe Daylight Time, UTC+02:00)
Great article! The three reasons you mention are really important.

I hope people don't get confused about the name "Value Object". It's important to think about the behaviour of the abstract concept you are creating, not of objects just holding a value. You're example is good, and I agree that address may not be.
Sunday, July 19, 2009 4:20:39 PM (W. Europe Daylight Time, UTC+02:00)
Thanks Torbjørn. I agree that the behaviour is the important part, though sometimes it's nice to have a general name for things, which I find Value Object is. It might even be/become a buzzword, but that's OK as long as this type of thinking gets communicated/picked up by Mort.
Sunday, July 19, 2009 11:55:47 PM (W. Europe Daylight Time, UTC+02:00)
Good read, and a very useful concept for sure :) I however don't agree with you on the Address statement. I think an Address is a Value Object, just because it has an ID in many implementations basically means those implementations are wrong ;)

One other thing I believe an Value Object should implement is the IEquatable<T> interface so you can compare different instances and override the == and != operators.

public class Address : IEquatable<Address>
{
public string Street { get; private set; }
public int Number { get; private set; }
public string ZipCode { get; private set; }
public string City { get; private set; }

public Address(string street, int number, string zipCode, string city)
{
Street = street;
Number = number;
ZipCode = zipCode;
City = city;
}

public virtual bool Equals(Address other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;

if (Street != other.Street) return false;
if (Number != other.Number) return false;
if (ZipCode != other.ZipCode) return false;
if (City != other.City) return false;

return true;
}

public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((Address) obj);
}

public override int GetHashCode()
{
return SomeHashCodeGenerator;
}

public static bool operator ==(Address left, Address right)
{
return Equals(left, right);
}

public static bool operator !=(Address left, Address right)
{
return !Equals(left, right);
}
}

hmmm I don't know how to do code formatting here :) so it looks like crap, and it was written without compiler check so crap it is, but you get the idea :)

-Mark
Monday, July 20, 2009 12:08:23 AM (W. Europe Daylight Time, UTC+02:00)
Mark,

I never said Address is not (or never) a Value Object. I merely said it serves (in my opinion) as a bad example, meaning there are better examples where the reader does not associate it with something that might have an Id.

As for using IEquatable that is an interesting concept, but it is not about what a VO is. I defiantly see its value, but I'm not sure I would enforce a rule on my VO's to implement it. Maybe (and I know my blog comment windows is not optimized for code) an example of usage would convince me otherwise, but my current understanding does not.
Monday, July 20, 2009 12:22:41 AM (W. Europe Daylight Time, UTC+02:00)
The difference between Entities and Value Objects is that an Entity has an ID to identify it self and a Value Object identifies it as a whole (my understanding of it anyway) So that you can have two different objects representing the same data:

Entity
User user1 = new User(1);
User user2 = new User(1);
User user3 = new User(2);

user1 == user2
user2 != user3

Value Object
Address address1 = new Address("street", 1);
Address address2 = new Address("street", 1);
Address address3 = new Address("lane", 1);

address1 == address2
address2 != address3

I know very dirty, but an example it is :)

And yes both Entities and Value Objects implement the interface, and no I wouldn't do it for very simple types, but the more complex ones yes why not. And this also shows that an Address doesn't need and ID ever (I done it wrong many times myself).

-Mark
Monday, July 20, 2009 12:26:05 AM (W. Europe Daylight Time, UTC+02:00)
Perhaps my example would be better if I said:

User user1 = UserRepository.Get(1);
User user2 = UserRepository.Get(1);
User user3 = UserRepository.Get(2);

user1 == user2
user2 != user3
Monday, July 20, 2009 2:29:02 PM (W. Europe Daylight Time, UTC+02:00)
Just a side note: Remember that there are domains where it makes sense to have addresses as entities. In one of my previous jobs working with direct marketing it made perfect sense.
Wednesday, February 17, 2010 7:02:31 PM (W. Europe Standard Time, UTC+01:00)
Hi Jon,


Just stumbled upon this link from a co-worker's email. Good introductory articles on value object. Just wanted to noted that having a interface for every single domain object is consider a anti-pattern for many.

http://www.lostechies.com/blogs/jagregory/archive/2009/05/09/entity-interface-anti-pattern.aspx

Wednesday, February 17, 2010 8:35:02 PM (W. Europe Standard Time, UTC+01:00)
Hi Herman,

I absolutely agree. In the domain model we've created we don't use interfaces for entities and value object, unless there is a really good reason for it. It's defiantly not by default, so very good point.
OpenID
Please login with either your OpenID above, or your details below.
Name
E-mail
(will show your gravatar icon)
Home page

Comment (Some html is allowed: a@href@title, b, blockquote@cite, em, i, strike, strong, sub, sup, u) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.  

Live Comment Preview
RSS RSS - Comments Twitter LinkedIn
         
SEARCH
 
 
         
TOP POSTS
   
         
NAVIGATION
   
         
CATEGORIES
  .Net (61) ADFS (3) Agile (30) Ajax (5) Architecture (20) Articles (1) ASP.NET (6) ASP.NET-MVC (1) Blogging (12) Books (2) BPEL (1) CleanCode (1) CloudComputing (7) Community (4) CSharp (11) DasBlog (5) Database (2) DDD (5) Deployment (16) DSL (1) Events (38) ExtremeProgramming (6) Fun (6) Gadgets (4) IIS (10) InfoQ (4) Java (2) Lean (3) Linq (2) MemoryLeaks (5) Microsoft (37) MVC (1) NDC (2) NNUG (36) Other (10) Patterns (9) Performance (3) Scrum (17) Security (7) ServiceBus (1) Silverlight (4) Software (19) TeamManagement (11) TechEd (7) Testing (4) Tools (25) TvGuide (1) WCF (8) Web (15) WebDeploy (1) WIF (3) Windows (10) Vista (15) VisualStudio (16) WiX (9) Work (16) Workflow (3)  
         
ARCHIVE
   
         
BLOGROLL
   
         
ON THIS PAGE...