1

I am reading specific parts of Martin Fowlers refactoring book again (the areas I was not clear about the first time round). I am looking at the Extract Method chapter at the moment. I can understand why Extract Method is beneficial; for example:

1) Inheritance and overriding

2) Clarity for the user of the class

Say I have some code like the below ( This is a DDD domain Service). Is this a candidate for Extract Method?:

    public IEnumerable<KeyValuePair<int, int>> CalculateDenominationsFor(int cost) 
        {
            var target = cost;
            foreach (var denomination in currency.AvailableDenominations.OrderByDescending(a => a))
            {
               var numberRequired = target / denomination;
               if (numberRequired > 0)
               {
                   yield return new KeyValuePair<int, int>(denomination, numberRequired);
               }
               target = target - (numberRequired * denomination); 
            }
        }   

I guess I could extract the following lines of code to methods:

target = target - (numberRequired * denomination); 

and:

yield return new KeyValuePair<int, int>(denomination, numberRequired);

The concerns I have about my two ideas above are:

1) They would be private methods so no benefit to the caller.

2) The class is currently sealed so no Inheritance benefits.

Is there any guidance available stating when to use Extract Method? Am I overthinking this? I am trying to apply this principle of least astonishment and find myself overthinking a lot recently.

  • The biggest mistake I can see in this method is the overuse (IMHO wrong use) of var. I had to read it three times to see all that variables are integers, and the code makes an integer division. Do yourself a favor and write int instead of var, that is not even more typing. – Doc Brown Jan 27 '18 at 12:19
  • Btw, this might be clearer if you write target = target % denomination, i.e. the remainder after giving that change. It then becomes clear that every line is integral to the solution, and nothing is worth extracting. (Except maybe fetching and ordering the denominations? Dunno. This method should arguably be called GiveChange(), and be a member of a currency class.) – amon Jan 27 '18 at 14:04
  • @amon, I see what you mean about putting the method in the Currency class. However, I am planning to encapsulate Cost in a method (value object), so I think it makes sense to use a Domain Service, which operates on: Cost (value object - which may have methods for calculating discounts etc) and Currency. Do you agree? – w0051977 Jan 27 '18 at 14:31
  • the biggest mistake is the potential infinite loop – Ewan Jan 27 '18 at 16:24
  • @Ewan, would you elaborate? – w0051977 Jan 27 '18 at 16:28
5

Yes I believe you are overthinking it! You should not look for "candidates for refactorings". You should look for code which require improvement and then look for refactorings as the possible tools to improve the code.

So the question is if the code in question:

  1. Has a problem
  2. This problem can be alleviated by applying a refactoring

I don't really see the two expressions in question as problematic, and I don't see how they are improved by the refactorings you suggest.

(The method as a whole could probably be clearer though, I cant really figure out what is going on. But that might just be lack of context.)

  • Thanks. +1 for the two points. Could you explain what you mean by: "The method as a whole could probably be clearer though". Does it need comments or better variable names etc? – w0051977 Jan 27 '18 at 12:39
  • 1
    @w0051977: as I already wrote, don't use var when it is not obvious from the specific line which type the declared variable gets. Especially when it is important for how the code works. – Doc Brown Jan 27 '18 at 13:34
  • 1
    Absolutely do ••not•• change those var’s. I’d change the variable names though. target confused me until I worked out it was the remaining cost. So call it that. And I’d be tempted to change numberRequired to eg denominationQuantity, but that’s less of an issue. One things for sure though: breaking this function up into sub-functions would almost certainly make it more complex. So leave it as it is. – David Arno Jan 28 '18 at 8:36
  • 1
    It is crucial to understand the division is an integer division. This is why I didn't understand the code at first, since it is not obvious. So I agree with the doc that you should be explicit with the type or or otherwise indicate this. Also agree with Arno about the naming. – JacquesB Jan 28 '18 at 9:28
  • @DavidArno: so you prefer to leave a var instead of int, even when it obfuscates the code? Do you prefer code which is hard to read, or why? – Doc Brown Jan 28 '18 at 22:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.