Refactoring and the Ubiquitous Language | Greg Young


I was reading this morning an interesting post to the domain driven design list. I began replying on the list but as my answer started to become more than one paragraph figured it might be better to drop the answer on the blog.

The basic scenario as described is:

What we used to call an ‘Actor’ on an Order is now going to be called.
‘Collaborator’ on a Form in the UI.Collaborator is not a bad word, its a quite good.
Should I now do search and replace in our code in order to use the new word ?

This is a very common scenario when working with a domain model over a period of time. What something is called changes. This is especially prevalent when we are working on a domain model where we start out with a naive viewpoint as is often the case in non-formalized models. In these cases very often in business experts are “learning as we are doing”.

The asker goes on to mention:

My Product Owner (PO), and team member would think I had been smoking crack or
worse if i came up with a suggestion like that.
Anyway We have used the old word Actor in a webservice contract, so that is not
easily changed. (I know i could introduce ‘Collaborator’ and by time make actor
obsolete.I know common sense would suggest not to get religious, and simply accept the
old word. How ever i do feel tempted to use the new word.Eric Evans uses a term like “Hammering the ubiquitos language”. Which i
understand as “Its really really important to use the language/ concepts of the
Project Owner/Users”

A few people have jumped in with responses. Many suggest that doing the refactor is ok.

Dan Haywood mentions:

I have to say that we change names all the time.  But then, I work with naked objects-pattern [1] frameworks [2], [3] where there are very few DRY violations… so it’s no great hardship.

There is however a subtlety in the question that seems have been missed by many and it is actually a huge problem when dealing with the Ubiquitous Language. Going through and renaming Actors to Collaborators inside of the model is not really a big deal and should be done. However the asker mentions as well a webservice contract!

The webservice contract is a wire protocol. Generally we do not just “refactor” wire protocols. The reason why is that doing so is a breaking change for clients. If we broke the wire protocol we would as an example need a big bang release of all consumers of the protocol as well as ourselves. This causes quite a dilemma when talking about refactors for the purpose of the ubiquitous language. Wire protocols are harder to change and require more planning than internal models. This is an issue that is too often overlooked.

The first question that needs to be asked is. By default will we be upgrading all clients concurrently with the backend anyways? If so then no big deal. I know of many frameworks that use this model. This does however necessitate a big bang release. If you have many disparate clients or are risk adverse for deployments this may not be possible. I believe the naked objects framework mentioned by Dan takes this approach though after seeing some presentations they may be on the third option today.

Note that very often people think incorrectly about this question. If my domain is used in a web server as example then I blue/green deploy it would seem I would be ok (client is the web server). But what if some received a page from the first then posted to the second. This may be an entirely acceptable business risk but remember it exists.

The next question is. Do we want to versionize our wire protocol. I could always take our old method that includes actor and create a new method that then uses collaborator. Old clients could still use the old one new clients would use the new one. We could even deprecate the old method after some period of time. You can imagine however with non-matching UIs and various versions around this can get confusing both for the dev teams and for the developers. We have to be very careful when dealing with messaging contracts.

A third option exists. The third option is not something that we can do at the point in time of the question as we would have had to make a decision much sooner in the development process. What if instead of using webservice contracts we had decided to use a HATEOAS RESTful api? With such a client I could make changes like this without affecting any of my clients.

It is important to remember that data on the inside is often different than data on the outside. A HATEOAS based api will often help isolate yourself from these types of changes in the future. There are however very few people using HATEOAS based apis over domain models. Instead largely due to tooling that is being given to us “restful” tends to mean “expose my objects as resources”. The question above is the exact situation that a HATEOAS based api can serve well. Keep these kinds of scenarios in mind early when choosing an api over your model!