Tiny Types

There’s a pattern I’ve used with great success a couple of times now that tends to provoke strong reactions in developers when they first see it. I’ve had comments along the lines of “that’s horrible!”, “ugh” and “that’s way too much work”. The pattern is this: the encapsulation of simple built-in types within domain specific classes. Sounds simple and it is.

Lets take a concrete example:

public class Customer {
private final String firstName;
private final String familyName;
private final int ageInYears;
private final int heightInCentimetres;

public Customer(String firstName, String familyName, int ageInYears, int heightInCentimetres) {
this.firstName = firstName;
this.familyName = familyName;
this.ageInYears = ageInYears;
this.heightInCentimetres = heightInCentimetres;
}
}

Fairly standard stuff. But note the constructor signature: string, string, int, int. Not really very expressive and exceedingly easy to get the parameters out of order. But who would get someone’s first and last names mixed up? Ask any Chinese person how often that happens. They place their family name before their given name. Also, strings and integers are not usually domain concepts unless you are writing a compiler. Someone’s first name is not interchangeable with their last name the way two strings are. So how about this:

public class Customer {
private final FirstName firstName;
private final FamilyName familyName;
private final Age age;
private final Height height;

public Customer(FirstName firstName, FamilyName familyName, Age age, Height height) {
this.familyName = familyName;
this.firstName = firstName;
this.age = age;
this.height = height;
}
}

It is at this point that most developers recoil. No way do I have time to add an entire class just to wrap a string! Or two entire classes in this case! Actually, it’s four new classes. All of which I wrote while writing this post. There is a reasonable amount of boilerplate. Including toString, equals, hashCode and a getter makes for about 40 lines per tiny type, almost all of which can be condensed into an IDEA template. And most systems have a finite number of domain concepts so the rate of adding these tiny types isn’t very high and drops off fairly quickly.

But why do this? I consider it playing to the strengths of a statically typed language. Java will never be as Ruby as Ruby, but it can be much more Java than Ruby ever will. All sorts of useful things start to happen when the library types and primitives have been banished from your api. Now the compiler can spot transposition errors. Equals and hashCode can be implemented with domain specific semantics. It’s much harder to accidentally pass dollars into a method that was expecting pounds sterling (but actually took a double so it could have been anything). Readability is greatly improved. Automated refactoring, code completion and code navigation all gain a new level of power. ‘Find usages’ on the FirstName class produces far more useful results than doing it on the String class.

You probably still don’t fully believe me if you haven’t tried it, but this is one of those times where cognitive dissonance has got it wrong. It really is an exceedingly useful approach.

About these ads