In the previous post we were facing the problem demonstrated by the diagram below.

Our FacebookMessageParser needs an instance of AllSocialNetworks so that it can create valid Users coming from Facebook. The only implementation we have for the AllSocialNetworks interface is UserRepository, and this implementation needs a FacebookMessageParser. That’s a circular dependency, it becomes impossible to instantiate the objects above without breaking invariants.
The invariant of an object must be always fulfilled; once the invariant is broken the object is not valid anymore and your system is in an abnormal situation –i.e. I would expect it to throw exceptions like crazy and/or eventually die in pain.
The problem seems to be that we don’t have a single place that knows all the required information to create a User. In our system we have a situation where all Users have Facebook accounts, but some of them have Twitter accounts as well. For those with both types of account we must construct the user object with information coming from all Social Networks.

The first thing we thought about was that our problem was in how the User object was being constructed. One-step instantiation wasn’t working. Turns out that this is a common problem in Object-Orientation, so common that there is an old pattern that deals with it: the Builder design pattern. One of the consequences of this pattern is:
It gives you finer control over the construction process. Unlike creational patterns that construct products in one shot, the Builder pattern constructs the product step by step under the director’s control. Only when the product is finished does the director retrieve it from the builder. Hence the Builder interface reflects the process of constructing the product more than other creational patterns. This gives you finer control over the construction process and consequently the internal structure of the resulting product.
That sounds like exactly what we need here. So we draft a UserBuilder.

This object can be passed to the multiple parsers so that each one of those can populate it with the bit of information that it provides. In the end we call the createUser() method and receive a valid object back.
The next problem: who instantiates the Builder? The UserRepository is supposed to manage the lifecycle for the User, therefore looks like the perfect candidate. What happens, though, when we have a list of users instead of a single one? It sounds that this would be as simple as an operation that maps from one list of Builders to one list of Users:

But the Repository doesn’t know how many Builders should be created -the objects are complex enough so that a UserListBuilder is not an option. Sometimes the FacebookMessageParser is the one who knows how many Users should be created, in other situation the list is known only by the TwitterUserParser.
At that stage our team designed a very complicated strategy that would let the Builders be created in multiple different points depending on the situation. When you get to such complicated solution is possible that you are be missing the point entirely.
We started to realise that our problems may be being made worse given the heavy coupling between parsers, gateways and the Repository. In this post we are looking at only one pair of parser + gateway and it may look like it’s not a big deal, but in the system we had more than ten of those pairs.
The Repositories definitely know a lot more about the internals of each system than they should. Why would it care if Twitter data comes from messages we parse or from objects that we have, say, in cache? It shouldn’t!
The biggest problem that all this coupling was causing in our development process was in our Ubiquitous Language. The business people talked used to say something like “then we get the user profile from Twitter”, but in our heads we had to do the mental mapping –and mental mapping is bad- between the business lingo and what actually happened inside our model. To reduce the noise we created then objects that represent the systems we talk to.
These Facebook and Twitter objects –we called them system abstractions- were modelled after what we, as a business, need from those systems. The technical details about the need to establish a connection and then parse a message were encapsulated by those. We did increase the number of classes, but we reduced the size and complexity of them all.
One of the good things that this refactoring provided was that we could see some interesting patterns in our model that were previously hidden in the messy relationships. Take a look at a subset of the Facebook interface, for example:
The class that represents Facebook knows about our Users. It receives them as parameters and instantiates that class. Why the hell would Mark Zuckerberg care about our system? What that means, in a practical sense, is that changes that affect only our user have the potential to change our Facebook abstraction. The class changes if the Facebook API changes or if User changes. Having more than one reason to change is a smell, as Uncle Bob says:
Why was it important to separate these two responsibilities into separate classes? The reason is that each responsibility is an axis of change. When the requirements change, that change will be manifest through a change in responsibility among the classes. If a class assumes more than one responsibility, that class will have more than one reason to change.
If a class has more than one responsibility, the responsibilities become coupled. Changes to one responsibility may impair or inhibit the class’s ability to meet the others. This kind of coupling leads to fragile designs that break in unexpected ways when changed.
And that was true. A quick look through SVN history shows that every time there was a change in User we had to change at least one system abstraction -and we have many of those types of classes. In most cases those abstractions that were changed together with User had no real relation with the change being made.
It became clear that each of our third-party systems were actually Bounded Contexts. In Domain-Driven Design, Bounded Contexts are boundaries that we create around a model to isolate it from other models. We not only define what goes in and what stays out of a model, but we also define how different models relate.
We had already defined that those Bounded Contexts could only be accessed through their system abstraction. What we had to do was to remove the dependency from the third-party Bounded Contexts to our Domain Model.
We are going to see how we approached that in the next post.



1 Response to “Everyday Tales: Anatomy of a Refactoring – Part 2”