Just Say No to “Magic Numbers”

I’m serious, watch out for Magic Numbers, they will cause you no end of headaches if you don’t get them under control from the start. I’m not talking about the musical brothers and sisters from Hanwell, (although if someone could get them under control and convince them to stop producing bland music I’d be forever grateful). No I’m talking about those mysterious numbers that appear in rules and formulae without any apparent meaning.

It’s easy enough to do, who hasn’t written a rule like the following:-

  IF transaction_code <> 12 AND transaction_code <> 15 AND transaction_code <> 18 THEN 
    INCLUDE
  ENDIF

That’s all well and good but what about when the same conditioning is used in several places, often in conjunction with other conditions? For example

  IF transaction_code <> 12 AND transaction_code <> 15 AND transaction_code <> 18 
    AND transaction_value > 0 THEN 
    INCLUDE
  ENDIF

and maybe another version for values less than zero

  IF transaction_code <> 12 AND transaction_code <> 15 AND transaction_code <> 18 
    AND transaction_value < 0 THEN 
    INCLUDE
  ENDIF

It doesn’t take long before you have the same conditions repeated again and again throughout your code with no indication of the business reasoning behind them. What happens if a new transaction code is created that also needs to be excluded in the same areas, are you going to go through every rule to check if it’s needed? Easy enough if it’s only in a handful of places but if there are lots of places that the condition is used it’s very easy to miss one when you need to make changes. Furthermore if instead of the relatively simple code above you have something like the following:-

IF (product_code<>"H1IB" AND product_code<>"H1FB" AND product_code<>"H1FD" AND
    product_code<>"H2IB" AND product_code<>"H2FB" AND product_code<>"H2FD" AND
    product_code<>"H3IC" AND product_code<>"H3FC" AND product_code<>"H3ID" AND
    product_code<>"H3IG" AND product_code<>"H3FD" AND product_code<>"H4IE" AND
    product_code<>"H4IF" AND product_code<>"H4IG" AND product_code<>"H4IH" AND
    product_code<>"H4IN" AND product_code<>"H4IO" AND product_code<>"H4FE" AND
    product_code<>"H4FF" AND product_code<>"H4FG" AND product_code<>"H4FH")
THEN
    IF (product_code="H100" OR product_code="H200" OR product_code="H300" OR
        product_code="H400" OR product_code="H10F" OR product_code="H20F" OR
        product_code="H30F" OR product_code="H40F" OR startsWith(product_code, "H1I") OR
        startsWith(product_code, "H2I") OR startsWith(product_code, "H3I") OR
        startsWith(product_code, "H4I") OR startsWith(product_code, "H1F") OR
        startsWith(product_code, "H2F") OR startsWith(product_code, "H3F") OR
        startsWith(product_code, "H4F") OR product_code="H10L" OR product_code="H20L" OR
        product_code="H30L" OR product_code="H40L") AND (product_count_I=1)
    THEN
        // do something
    ELSE
        // do something else
  	ENDIF
ENDIF

This isn’t a worst case scenario, this is taken from a real application, and the checks against the product_code variable are repeated in at least 20 different components and rules with subtle variations like the check against product_count in this example.

Whilst it may make perfect sense to the developer that is building the initial application, give it a few months down the line and a few staff changes and it won’t be long before any changes to this conditioning become a real headache with no one understanding the business reasoning behind the rules.

In this case the checks against the product_code are meant to include content for a particular type of product (bundles) but exclude a subset (in this case it’s an insurance product that only provides breakdown cover.

How much easier is it to read this instead?

  IF bundled_product AND NOT breakdown_only_product THEN
    IF product_count = 1 THEN
      // do something
    ELSE
      // do something else
    ENDIF
  ENDIF

You can then write separate functions to set the boolean variables bundled_product and breakdown_only_product, then call the functions each once from a customer timing formula. This way not only is your code instantly more readable, but if new bundled products or breakdown only products are added at a later date you only have to update a couple of functions instead of dozens of rules.

It’s all about making it easy for yourself and your customers 🙂