Field Typing

We’ve all been on Java projects with surprisingly weak typing. You know the problem: we read all data from some external source as String values and pass those strings all over the place by name, even if they actually contain interesting things like URLs, IP addresses or even human-readable dates. This leads us to creating helper functions to process those strings.

Java is not a dynamically typed language, and when we use it with data from the dynamically typed world, or from a world with a more restrictive type system, it’s easy for there NOT to be strong typing in our design. As a friend once quipped – this isn’t strong typing, it’s STRING typing.

In a project I’m currently involved with, we’re using a pattern that’s the polar opposite of this. There are lots of reasons behind it, but let’s look at the problem we’re solving and its solution before trying to justify what seems like a radical approach.

Before this solution was applied, imagine the following class, modelling data from a table in a database:

public class DocumentBookmark {
  private UUID id;
  private UUID publicId;
  private UUID fkDocument;

  public DocumentBookmark(UUID id, UUID publicId, UUID fkDocument) { ... }

As you can see, this object happens to have three identifiers in it. Each identifier is structurally a UUID, and their purposes are separate:

  • Primary key of this table
  • Foreign key to another table
  • A public-visible identifier, possibly generated externally to the system

It’s pretty obvious that crossing the values over would be catastrophic. It’s also clear that it’s easy to do. One UUID can be assigned from another quite easily. The constructor’s signature is just (UUID, UUID, UUID).

You can probably guess where this is going. What if each of the three values had its own type.

There’d be a base class for simplicity:

public abstract UUIDIdentifier {
  private final UUID identifier;

  protected UUIDIdentifier(UUID identifier) {
     this.identifier = identifier;

  // for serialising back to the DB
  public UUID toUUID() {
     return identifier;

And then subclasses for each type:

public final DocumentBookmarkId extends UUIDIdentifier {
  public DocumentBookmarkId(UUID identifier) { super(identifier); }

public final PublicId extends UUIDIdentifier {
  public PublicId(UUID identifier) { super(identifier); }

public final DocumentId extends UUIDIdentifier {
  public DocumentId(UUID identifier) { super(identifier); }

And then the original parent would be this:

public class DocumentBookmark {
  private DocumentBookmarkId id;
  private PublicId publicId;
  private DocumentId fkDocument;

  public DocumentBookmark(DocumentBookmarkId id,
                 PublicId publicId,
                 DocumentId fkDocument) { ... }

This is not how I’m accustomed to solving the modelling of objects, and it seems horribly cumbersome to have to write a type – even if the base class does all the work – for every field you use. Except you’re not. You’re creating types to represent types of fields at a more granular level. The foreign key DocumentId type is also the same time as the primary key on the Document table.

The advantages of this:

  • It’s much more obvious if you’re wrangling the wrong value into the wrong field because you have to do more than just switch variable names
  • You have to consider the marshalling of data between weaker and stronger types – it doesn’t take much coding, but it becomes very intentional, rather than a happy accident of the default constructors and toString methods.
  • You don’t need to rely on variable names or named builder methods to help explain the purpose of a value – its type is doing a lot of the work.

As a bonus extra, the identifiers are immutable objects, which can be a handy discipline for enforcing better practices, along with thread safety.

This technique, which is especially helpful as a discipline to break people out of weakly typed thinking, is not for everyone or every project, but it’s been surprisingly handy on our current one.

I’d be interested in your comments.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s