Tuesday, February 9, 2016

Refactoring - Decompose Conditional

Simple code is easier to understand and maintain. One of the aim of refactoring techniques is to be sure the code is as simple as it can be.

This refactoring can be applied in the case of a series of conditions that might be to difficult to follow and easy to get it wrong.

Let's write some code that is calculating the taxes one has to pay. In our example, there are 5 levels of tax, depending on the income and number of kids.

if (income < 1000) && (kids == 0) { //level 1
    tax = income * 0.2
} else if (income < 1000) && (kids > 0) { //level 2
    tax = income * 0.1
} else if (income < 2000) && (kids == 0) { //level 3
    tax = 200 + (income - 10000) * 0.3
} else if (income < 2000) && (kids > 0) { //level 4
    tax = 100 + (income - 1000) * 0.2
} else {
    tax = 400 + (income - 2000) * 0.4 //level 5
}

It is not easy to follow the code, let alone change. Imagine what would have happened if there were 20 levels instead of 5.

We can simplify it by extracting a function for each conditional and each branch:

if checkLevel1() {
    tax = computeTaxLevel1()
} else if checkLevel2() {
    tax = computeTaxLevel2()
} else if checkLevel3() {
    tax = computeTaxLevel3()
} else if checkLevel4() {
    tax = computeTaxLevel1()
} else {
    tax = computeTaxLevel5()
}

Of course, each of the function are defined as follows

func checkLevel1() -> Bool {
   return (income < 1000) && (kids == 0)
}

func computeTaxLevel1() -> Double {

    return income * 0.2
}

The other ones are similar.

Now the code is clear and also for changing one level, one knows exactly where to do it: in the function corresponding to that level.

No comments:

Post a Comment