DDD – Global Unique Identities vs Surrogate Keys

Architecturedomain-driven-designobject-oriented-design

Let's start with an example: we have an entity: Book. It has unique identity: Isbn – a value object that wraps a String. This is an UUID.

The Book entity also needs a surrogate id from the repo (sql db). We need it so we can e.g. find the books in faster way, since databases find by number faster then by string.

From what I read, the surrogate key should be hidden from the Books interface. But we want to use it, to locate books much faster.

How to deal with this in a proper way?

[A] We can simply add a getSurrogateId() (or any better name) in the Book. This pollutes the entity, but its KISS.

[B] We can have the repo responsible for finding the surrogate keys for the natural ones. For example, BookRepository may have the following method:

long toSurrogateKey(Isbn isbn) {
     // lookup the cache
     // if not found, lookup the db
}

to return the surrogate key – of course, these values can be cached locally, so we do not need to search db every time. This method should not be public (right)?

[C] We can go even further: to think about surrogate key as a repository specific one. Book may be an interface, and SqlBook may be an repository-made implementation. This SqlBook implementation may then store any additional information needed for the repository. In this case, we would have the surrogate key as one of the properties of SqlBook – and we do not care it is visible, as users of SqlBook only sees it as a Book, i.e. not knowing about the surrogate id.

So above method becomes (defined in SqlBook class):

long toSurrogateKey(Book book) {
     return ((SqlBook)book).getSurrogateId();
}

The only drawback here is that Book (and other entities) must be created by a Factory that is repository-aware. In other words, we would need to have SqlFactory implementation of some factory that creates SqlBooks for us.

Any wisdom on this?

Best Answer

We need it so we can e.g. find the books in faster way, since databases find by number faster then by string.

Surrogate keys should primarily be added because they provide you a uniform way for building your primary keys, not because of any hypothetical performance issues. They will help you to avoid having business data like an Isbn distributed over half of your model in separate places because you misuse them as foreign keys.

"From what I read, the surrogate key should be hidden from the Books interface".

Maybe you just misunderstand the purpose of this? Surrogate keys are technical details which should be hidden when discussing the model with your domain experts, but it is perfectly ok to see them when you change your viewpoint to the implementation of the model. So go with [A], but make sure the getSurrogateId() accessor is not visible in your graphical form of your domain model.

Related Topic