value objects and “equality”

Today Corey Haines posted another great video interview with JB Rainsberger. This time the topic under discussion was Value Objects. Well worth a listen (go ahead, I’ll wait).

The main gist of the discussion was JB’s assertion that the distinguishing feature of Value Objects is that their equality depends on their state, as opposed to depending on their identity. Thus two 1-Leu notes are “equal” if and only if they have the same monetary value, even though they have different identities (for example, their serial numbers differ). JB then proceeded to extol the virtues of imbuing Value Objects with an equality function and I agree, but only up to a point.

I don’t doubt that creating a new Value Object class to wrap a primitive yields many benefits, and in many cases one of those benefits is to allow the writing of an equality operator for that new class, thereby simplifying much code. But right now, this week, I’m in the throes of a refactoring whose sole purpose is to allow the removal of such an equality operator, because two different views need to compare these values differently.

Going back to real money for a moment, suppose two people looked in their wallets and discovered they had the same amount of money. Does that make their wallets “equal”? I’d say it depends on who’s asking, and why; you might be comparing for total value, whereas I might compare for total number of notes, for example. It doesn’t really make sense for wallets to have an equality operator, and yet in many respects they are interchangeable Platonic values.

That’s a bit contrived, but I do think it’s generally the case that objects with a multi-dimensional value can have multiple valid “definitions” of equality — and that therefore, in such cases, equality is in the eye of the beholder. Does that invalidate JB’s argument? No, I don’t think so. The various kinds of “equality” of objects with a multi-dimensional value still satisfy his definition, and they are still value objects. I’m just being a pedant. Again.

factory method in ruby

During my refactoring homework last evening I noticed a little tug-of-war between two different coding styles, and after a restless night I’ll try to analyse here what was going on…

Deep inside Reek is a Source class, whose instances are responsible for converting Ruby code into abstract syntax trees for later examination by the various code smell detectors. Source code can come from many different places, and so Source has a number of Factory Methods like this:

class Source
  def self.from_io(ios)
    new(ios.readlines.join)
  end

  def self.from_s(code)
    new(code)
  end

  def self.from_f(file)
    from_path(file.path)
  end

  def self.from_path(filename)
    new(IO.readlines(filename).join)
  end

  # ...
end

(The factory methods also do some other stuff, which I’ve elided for clarity.)

As the refactoring exercise proceeded, I found that one of these methods came to be called from only one place. So I considered inlining it, and that’s when the tug-of-war began. Part of me resisted inlining the method, even though that’s what the code seemed to want. I argued that the Factory Methods were “potentially useful”, that they represented the Source abstraction and helped to document it; the code pulled the opposite way. (My wife was sitting across the room, so I kept this argument quiet inside my head; maybe that’s part of my problem.) Anyway, to cut a long story short, at the end of my refactoring session the code had changed to (something very similar to) this:

class File
  def to_source
    Reek::Source.new(self.path)
  end
end

class IO
  def to_source
    Reek::Source.new(self.readlines.join)
  end
end

class String
  def to_source
    Reek::Source.new(self)
  end
end

The Gang of Four didn’t name this pattern, so I’ll call these methods “Converters”. (Please tell me if this pattern has a more well-known name.) They’re just like Factory Methods, but they sit on the class being converted from instead of on the class being converted to.

The argument between me and the code was between the forces in favour of each pattern. In favour of the original Factory Methods:

  • In C++/Java — the world in which the GoF did their work, and where my roots lie — this is the only place to put the methods;
  • the dependencies point from Source to its origins (File, String, IO et al), which seems quite natural;
  • the compiler checks that the Factory Methods are called with the right types of input object;
  • all the ways to create a Source object are together, so they are easy to find and compare.

In favour of Converters:

  • We could later introduce new ways to create a Source without opening up that class;
  • they are instance methods, and hence just a little more natural, testable and “object-oriented”;
  • methods such as to_s, to_a, to_i are idiomatic in Ruby, which enhances the Communication value of this approach;
  • you need a File (for example) in order to call the Converter. (Actually, I’m not sure this counts as an advantage, because it prevents duck typing.)

On balance, I feel the C++/Java form of Factory Method has many advantages. But I switched the code to use the Converter form, mainly to see what would happen. I could easily switch back again now I’ve seen the forces laid out for comparison in this blog post…