A brief exploration to help you save on instantiating times
At Infraspeak, the entire engineering team gets a couple of days every month to dedicate fully to pet projects. As my friend, Nelson, and I worked on our automation Bot, we introduced the first Entities to our domains without first noticing that we were creating invalid instances. This article shows why those instances were broken from the start and how to ensure we always work with valid instances even before persisting them in a data store.
Entities are defined by a thread of continuity and identity. This means that due to having a unique ID, whenever their properties’ values change, it’ll still be the same Entity, and we’ll always be able to reference it (that’s the continuity part).
When developing software, it’s broadly accepted that we should strive for immutable objects. If we want to change something inside immutable objects, we make new instances with the updated values. This prevents an object from being unintentionally mutated during the execution of the application logic, probably putting it in an invalid state.
I won’t delve too much into this pattern (rain check for another post), but the point is that when working with immutable objects, they should be in a valid and usable state. Anywhere that accepts that object doesn’t need to worry about constantly checking for its validity.
So, if having an identity via a unique ID completely defines an Entity, and it should be considered immediately valid upon instantiation, then using sequentially-generated numbers from a data store as the source of the Entity identity is a problem. And here’s why: we can’t safely predict what the next number is, and it’s not even the Entity responsibility to do so, leaving us in a dilemma: we need to instantiate an Entity to persist it and get that ID, but we can’t because to instantiate it we need to have an ID. So, what to do?
A naive, instinctive workaround would be to accept two types for the ID property: an
integer or a
null. This does fix the problem of instantiating the object but doesn’t make it valid. We implicitly created a dependency on the data store now because we need to persist the entity first and create a new instance with the actual ID. This needs to be done before we can use it further in the application.
The thing is, although broken, this is the most common implementation that I’ve seen when working with Entities. I, too, have done it this way. Still, I’ve recently found another way of working with totally valid Entities without requiring them to be persisted in the data store before being used in the application.
The trick is to drop the use of internally-generated sequential IDs from the data store at the application level and replace them with randomly, uniquely-identifiable IDs, like UUIDs. Using UUIDs, we can generate unique IDs and have fully valid Entity instances to work with immediately. This will also remove a hard dependency on the data store.
We can save on object instantiation times since we no longer need to recreate an Entity class upon persistence since there’s probably no new properties to fetch. Whereas before, we would need to do it to have the ID populated from the data store. The persistence of the Entity becomes an implementation detail.