Identify The Identity (Part II: Conceptual Application Identifiers)
In part I of this topic, I explained the problem and offered an alternative to exposing database keys as application identifiers. While this alternative is undoubtedly an improvement, it’s far from ideal. In this post we look at why.
The Need To Evolve
To recap, database keys should not be used as application identifiers. Instead I offered a simplistic and basic alternative using UUIDs, with 2 different technical implementations (code-generation or database-generation, recommending the former over the latter).
Wait, first UUIDs were a logical evolution to auto-generated database keys but now they’re simplistic and basic. Why? Well, UUIDs are still a technical solution to a more conceptual problem.
In general, we need to evolve beyond the technical and understand the conceptual. Then we will have software that is representational to the business domain in which it operates. And only then will we have truly useful software.
Meaningful application object identifiers is a quick win and a first step on that journey.
Understanding Your Domain
(Note: for the remainder of this post I will use the term technical identifiers to refer to the use of both database keys and UUIDs as identifiers)
Technical limitations of database primary keys aside, they are quite simply a database storage mechanism. Sure, they are a handy way to uniquely identify individual records in relational databases. But relational databases in most applications are for persistence of application data and nothing more. Why let your persistence mechanism bleed into your business domain functionality?
UUIDs are an algorithmically smart way (using the machine signature) of ensuring absolute uniqueness. Still, it couldn’t get more technical really could it? And who fancies having to remember a 32 digit, specifically formatted UUID to individually identify an item anyway?
Referring to the first post again, I stated “When you’re identifying application identifiers, you aren’t just looking at uniqueness”. This cannot be emphasised enough. In Eric Evans’ Domain Driven Design classic he explains
“it is common for identity to be significant outside a particular software system” – Eric Evans
What Evans encourages with DDD is to let the “domain drive your design”. In other words, let the domain indicate the identity of a domain object. Which sounds obvious doesn’t it? Yet time and again I see this being ignored and in it’s place an developer-crafted arbitrary identifier.
In my opinion what Evans fails to drive home is that when you do have a significant, meaningful identifier outside the software system (e.g. social security number, car registration plate, etc.) then this must be used as the application object identifier. By designing your object model to incorporate such identities you are not only accurately aligning your implementation closer to the business domain, but you are gaining and sharing a better understanding of the business domain with anyone else using this object model (this is valuable no matter how subtle it may seem).
Taking the easy way out by using a technical identifier is not only encouraging a lazy solution (McDonalds remember?), but its discouraging your development team to realise a better and more accurate design.
Of course Evans goes on to explain that although this is indeed common, identities are sometimes only important in the system context (exceptions to every rule of course), and that is ok. The main point I am trying to emphasise is that you should always look at the domain to identify an identity for your object. When there is one in the real world – use it. When there isn’t one, well the technical identifier may just have to do. In these cases, it is still preferable to use a UUID rather than a database key so that you are not exposing your database implementation.
As a footnote, I should highlight that all this advocating of application object identifiers over technical identifiers does not mean you do not use a technical identifier altogether.
Technical identifiers should still be used to maintain unique mappings between the application domain objects in your code and the records in your database tables. Conversely, do not make the mistake of dropping your technical identifiers altogether and using your application object identifiers as database keys. By doing this, your application object identifier has then just become your technical identifier. You are then letting the reverse happen; your application is now bleeding into your infrastructure. Unless you have no alternative you do not expose technical identifiers to the end user. Instead keep them separate (separation of concerns).
On all projects I have a design say on, I vehemently insist on making the technical identifier a private or protected attribute of objects, then making the application object identifier public and therefore consumable to the end user.