2 Comments
May 16, 2022·edited May 16, 2022Liked by Kevin Rutherford

An insightful set of articles Kevin, thank you. I particularly like this from #3:

"We really only have two levers to pull when it comes to having the code reveal our intentions: the names we give to things, and the set of things we choose to give names to. Together, these names should create a narrative that reads well to anyone who understands our domain."

I think there is a lot in this paragraph. I've long believed that a 'good' design will look roughly the same whether you derive it from the bottom up (i.e. by reducing implicit coupling, reducing repeated code, etc.) or the top down (finding the names that make sense within the business domain). My experience of such designs is they tend to survive both business and technical change better than ones that only make sense when viewed from one direction or the other (or neither!).

I've worked on a lot of systems of they type you're using as an example and concepts like catalogue and discount rule are always where you end up as they result in the cleanest code *and* have the most direct correspondence with the business domain. This shouldn't be a surprise; we have millennia of experience of pricing and selling things so we've already put a lot of effort into ensuring consistent and correct calculation of prices.

The reason I think this is important in this context is that us techies spend a lot of time thinking about what we refactor from (code smells) and the refactoring we apply (transformations such as extract method, etc.), but less time thinking about where we're refactoring to.

Again, in my experience, identifying code smells and applying common transformations will lead you to a better place, but aren't *necessarily* going to help you find that 'good' design. However, looking for transformations that fix code smells whilst taking steps towards a domain concept will lead to more maintainable code; code that is more accommodating of change whether than change is prompted by business or technical requirements

Looking ahead slightly to a more sophisticated iteration of your example, you can imagine a general set of pricing rules to deal with sales taxes, shipping costs, credit notes, perhaps surge pricing for digital assets. We shouldn't try to preempt these in the design if we don't need it today but as the need for each of these becomes apparent the domain gives us clues as to where our refactoring should go. And when you have multiple pricing rules, something is required to know what order to apply them in and which rules can't be combined. In the domain of over-the-counter sales this used to be the cashier, or a the sales person for more bespoke selling, until they were gradually superseded by software that acts as the 'pricing calculator' which is dominant domain concept today.

Expand full comment
author

Many thanks, Paul, for such a detailed response -- and I'm really pleased you like the articles!

I agree that a lot of refactoring discussion seems to undervalue the angle of domain congruence. And I wonder where this series of articles is going to take me next...

Expand full comment