Discount rules, part 2
In Discount rules, part 1 we found implicit coupling between three different classes in a shopping application written in Python. If you haven’t read that article yet, why not do that now and have a think about how you would refactor the code to deal with the coupling we found. Done that? Okay, let’s look for solutions…
For a moment, let’s go back to the case where there are only two instances of each of the values.
I can think of seven responses to the implicit coupling we found in the previous article:
Do nothing.
Have
DisplayBasketCommand
fetch the values explicitly fromBasket
.Have
Basket
fetch the values explicitly fromDisplayBasketCommand
.Keep the values in some third thing — let’s call it
DiscountRules
— and have Basket andDisplayBasketCommand
either fetch them or have them injected.Move
DisplayBasketCommand
inside ofBasket
.Move Basket inside of
DisplayBasketCommand
.Move both Basket and
DisplayBasketCommand
inside something else.
Options 1 and 7 don’t substantively change anything, so for the purposes of this article I’m going to discount them.
Let’s look now at options 5 and 6: neither of them really seems to “make sense”. The application has separated DisplayBasketCommand
from Basket
so that Basket
doesn’t need to know how to display itself, and yet both of these options would undo that separation. It doesn’t feel realistic to place either class inside the other.
So in reality only options 2, 3, and 4 are “meaningful” — that is, only options 2, 3, and 4 have any chance of producing code that represents our understanding of the domain.
In fact, the statement above is an important part of any refactoring process, and I want to stress it a little before moving on. We are working on fixing some implicit coupling because we want to improve the code’s habitability, and also we want our code to satisfy the 4 rules of Simple Design. The the implicit coupling we found violates the Once And Only Once rule, and in order to make it explicit we listed a bunch of potential solution designs, and then we filtered them using the Intentionality rule of Simple Design.
The key idea here — and I think we do this unconsciously a lot of the time — is that we are looking to pick a refactoring strategy for this problem that also helps the code to better express our understanding of the domain.
I think this is a general pattern that we’ll see time after time:
Identify some implicit coupling (a violation of the Once and Only Once rule) and decide that we want to make it explicit.
Identify options for our solution design.
Filter those options using the Intentionality rule, so that the option(s) we have left “make sense” according to our understanding of the domain.
What should we do if, as in our Basket example above, we still have multiple solution options. We could:
Try one or two and see which feels better. Or,
Test the options using further criteria, such as acceptance test scenarios.
What would you do in this situation?
Next time, we’ll go back to the case we found last time, in which those magic numbers are present in three classes. Stay tuned…