Class Responsibility Collaborator (CRC) cards can provide a lightweight and Agile tool for refactoring and developing software design hypotheses. In this post, we explore how one of our product delivery teams used this object-oriented design technique to refactor more productively.
The Alchemists, one of the product delivery teams at Simply Business, recently completed a major project to refactor part of our monolithic codebase for our insurance brokerage service. The project involved determining which quotes and leads should be transferred to a third-party and when. Part of the development work to implement this scenario had already been carried out on our core Rails application. However, as this no longer aligned with our technology strategy of breaking up our large codebase into components, the team was faced with how best to refactor the code.
We began by working on an architectural decision record (ADR) to define how to restructure the code and migrate it to one of our core gems - 'Opportunity Knocks' (hereafter referred to as 'OK'). The refactoring work to move this code from the core application to the component was not trivial so we used the idea of 'microsteps' (World's Best Intro to Test Driven Development - Joe Rainsberger) to move the code out gradually and eventually converge on the architecture envisioned in the ADR.
One thing lacking, though, was a sense of the bigger picture - something the team was quick to point out. So when Tim Mackinnon visited our London office, we were inspired to try out a technique used to teach object-oriented design in the 1980s - Class Responsibility Collaborator (CRC) cards.
Developed by Ward Cunningham and Kent Beck, CRC cards are what may now be considered old-fashioned index cards, used to represent objects or classes. At the top of the card, the developer writes the name of the class that will solve a particular problem. On the left is an itemised list of responsibilities the class has, and on the right is a list of collaborators (other classes) that will help fulfil some of those responsibilities. Ward's Wiki has more information on the CRC technique.
We began by writing CRC cards for our design as it currently stood and realised many immediate benefits; for example, difficulty in describing the responsibilities of some classes clearly and concisely.
We posted each card on our whiteboard, grouping classes and their collaborators together, which gave us the lay of the land fairly quickly. We then experimented with moving cards from the core application (Chopin) section of the whiteboard to the component (OK), to see if they made sense there.
This was great, because the cost of hypothesising and reasoning was almost zero. It enhanced the team's agility, and uncovered potential difficulties in moving a particular class. All of this led to critical conversations with teammates, and was possible without us writing a single line of code!
By using the CRC technique, we discovered some refactoring opportunities too: class naming, lots of collaborators and extracting classes, which we'll discuss further.
One class stood out in particular:
TransferService. Its responsibilities were to:
At the CRC card level, the class name wasn't as accurate as it could be. This raised two questions: 'Who/What was being transferred?' (presumably the customer) and 'To whom?'.
As a first pass, we drew up a new card with the same responsibilities and collaborators but with an improved class name -
TransferToBrokerService, and created a pull request to refactor the
TransferService. This stimulated some great naming suggestions from teammates and led us to identify a possible feature envy smell, which was tagged in code using
SMELL comments. We could then use, say, Rubymine, to filter for
SMELLs and address them easily!
Look at the card representing the
RequestFactory class below. What do you notice about it?
One thing that stood out was the number of collaborators. Any more and they wouldn’t fit on the card! That felt like a smell, and on looking at the tests, sure enough, there was a lot of complicated setup. The test was difficult to follow and resulted in another pull request to clean it up. Many collaborators were parsing objects from a form object, which prompted a hypothesis to extract a class that would be purely responsible for that.
Have a look at the card representing the
TransferToBroker class below:
It’s the one we renamed earlier. The trouble with this class is that it references low level detail (Daily Tally) in the component (OK). The Daily Tally object is used to keep count of how many customers have been transferred to a specified broker today. If the tally exceeds the maximum number of customers the broker can handle, our rules dictate that we transfer customers to BIBA, the British Insurance Brokers’ Association. Now, is it really the business of our core application (Chopin) to know this? Isn't this a little bit leaky? This led to another refactor, to move the incrementing logic over to the component (OK).
The first step was to group the logic to transfer the customer and increment the tally to another class, which is what the
TransferToBroker card represents.
Transfer To Broker (OK) is the new class that handles the transfer and tally update process. This microstep makes moving code to the component (OK) easier, as Kent Beck advises. Looking at the responsibilities now, they make much more sense in the core application. The final card looks like this. The responsibilities were easier to articulate and there weren’t too many collaborators required to fulfil them.
One thing that can be difficult is collaborating on CRC cards with remote colleagues. A colleague in another of our product delivery teams has been experimenting with Miro to overcome this impediment.
This is our design in its entirety.
In a follow-up post, we'll look at addressing the feature envy smell identified in the
TransferToBroker card and how to refactor in microsteps.
Want to know more about what it's like to work in tech at Simply Business? Read about our approach to tech, then check out our current vacancies.Find out more
6th Floor99 Gresham StreetLondonEC2V 7NG
Sol House29 St Katherine's StreetNorthamptonNN1 2QZ
© Copyright 2020 Simply Business. All Rights Reserved. Simply Business is a trading name of Xbridge Limited which is authorised and regulated by the Financial Conduct Authority (Financial Services Registration No: 313348). Xbridge Limited (No: 3967717) has its registered office at 6th Floor, 99 Gresham Street, London, EC2V 7NG.