In my last post I reflected the downsides of using numerical types for the primary key of an entity. We should avoid these issues all together by using UUID instead and in this post I will discuss the up- and downsides of this approach.

Using a UUID as the primary ID is simple:

@Entity
class Flat(
	@Id
	val id: UUID = UUID.randomUUID()
)

Generate the ID on the application

Similar to numerical ids we can generate it on the database as well. But for UUID this is not necessary. The reason we did this in the first place is that we needed to make sure that an ID is not used twice. A collision of UUID is very unlikely to occur.

Collision Probability

“To put these numbers into perspective, the annual risk of a given person being hit by a meteorite is estimated to be one chance in 17 billion, which means the probability is about 0.00000000006 (6 × 10^−11), equivalent to the odds of creating a few tens of trillions of UUIDs in a year and having one duplicate. In other words, only after generating 1 billion UUIDs every second for approximately 100 years would the probability of creating a single duplicate reach 50%.” ~Wikipedia

And what do we do when such error happens? We don’t need to establish any special handling of it. We throw an exception, cancel the transaction and let the client redo the operation. Like we would always do when something happens that we can’t handle.

But we get extraordinary benefits from UUID:

Offline Capability

We don’t need to generate the UUID on the database. We don’t even need to generate it on the backend. We can create it in the client. And this enables the client to create new entities without synchronizing them to the backend. This enables us to make the client very resilient to network issues. E.g. I implemented such behavior in a game I developed and that enabled us to support playing the game even in unstable environments like when you play on the train and drive through tunnels. It is an awesome experience for the users and does not require a lot of work on the application to achieve.

Easier (Unit) Testing

When you generate the UUID on the client or server you have much more control over it. And this is beneficial when you want to write unit tests for your entities. You can simply use the constructor. Generating it on the database relied on reflection and in the runtime between the setting of the id and the creation of the object it is in an unstable state. Have a look at the “Collection Problem” in my previous post.

Tedious Debugging

UUIDs are unhandy. Remembering that E209C805-C7D5-4C7A-8F02-37BEA845A405 is the ID of the entity you look at is of course harder then remembering 2837. This is a downside and everyone needs to decide whether that is a strong argument.

More Space

Of course UUID are larger than Int. You can do a whole evaluation of this aspect. You can even fill pages and whole blogs about it. But I don’t do that. In relation to all the other kind of data that we store nowadays it is a waste of time and energy. Space - in this scale - does not matter for 99% of the applications out there. If you work in an environment where it matters, sure, do the evaluation and make a proper decision. But for most of the developers our there it shouldn’t matter at all.