Contents

Long Method

Long Methods

Those are methods that contains a significant amount of code. There’s no rule for this smell, how long? 10, 20, 30 lines? Each case must be analyzed in its context.

It’s important that the method follows the Single Responsibility Principal, here’s a great video from Uncle Bob Martin about Solid Principles which covers SRP.

If we want to reduce the length of a method body

Extract Method

Suppose we have this code:

1
2
3
4
5
6
7
function printInfo() {
    printName()

    // Print address details
    console.log('street')
    console.log('number')
}

We can extract the address details into a new method.

1
2
3
4
5
6
7
8
9
    function printAddressDetails() {
        console.log('street')
        console.log('number')
    }

    function printInfo() {
        printName()
        printAddressDetails()
    }

Here we separated a piece of code to a new function and replaced the old code with a call to the method. Also, we removed the unecessary comment, since the function name is meaningful.

If we want to reduce local varibles and parameters before extracting a method

Replace Temp with Query

Sometimes, we have code that is not easily extracted, it depends on variables. Such as:

1
2
3
4
5
6
7
8
9
    function getDiscountByPrice() {
        const canGetDiscount = totalPrice >= 100

        if(canGetDiscount) {
            return totalPrice * 0.8
        } else {
            return totalPrice
        }
    }

We can replace the canGetDiscount variable with a new function.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
    function getDiscountByPrice() {
        if(checkCanGetDiscount()) {
            return totalPrice * 0.8
        } else {
            return totalPrice
        }
    }

    function checkCanGetDiscount() {
        return totalPrice >= 100
    }

Introduce Parameter Object

If we got methods with too many arguments, we can replace them with objects.

1
2
3
    function filterByDate(start, end) {
        // implementation
    }
1
2
3
    function filterByDate({ start, end }) {
        // implementation
    }

Instead receiving two parameters, we now receive an object with the data we need.

Preserve Whole Object

Similarly, we can preserve the whole object and not create variables to hold data.

1
2
3
4
    const start = dateToFilter.getStart()
    const end = dateToFilter.getEnd()

    const data = filterByDate(start, end)
1
    const data = filterByDate(dateToFilter)

We can replace a method with Method Object

Replace Method with Method Object

If we have many local variables and they are tightly coupled and we can’t apply Extract Method, we can try Replace Method with Method Object.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
    class Order {
        // ...

        function calculatePrice() {
            const someData
            const moreData
            const moreMoreData
            // perform some calculations here
        }
    }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    class Order {
        
        function calculatePrice() {
            return new CalculationPerformable(this).calculate()    
        }
    }

    class CalculationPerformable {
        private someData
        private moreData
        private moreMoreData

        function CalculationPerformable() {
            // construct the class as needed
        }

        private function calculate() {
            // perform the calculation here
            // it's possible to have another 
            // methods following SRP on this class
            // to assist it's main responsibility
        }
    }

If we have conditionals and loops

Decompose Conditional

Complex conditions can be decomposed into methods.

1
2
3
4
5
    if(client.isSilverVIP || client.isGoldVIP) {
        // do something
    } else {
        // do another thing
    }
1
2
3
4
5
    if(checkClientVIPLevel(client)) {
        // do something
    } else {
        // do another thing
    }

The method checkClientVIPLevel() would be responsible to check VIP Level of a client.

Extract Method

We can use Extract Method to handle loops.

1
2
3
4
5
6
7
8
    function printClientsName(clients) {
        clients.forEach((client) => {
            let name = client[i].firstName
            name += ' ' + client[i].lastName

            console.log(name)
        }
    }
1
2
3
4
5
6
    function printClientsName(clients) {
        clients.forEach((client) => {
            const name = getClientName(client)
            console.log(name)
        })
    }

Payoff

  • Classes with short methods live longer among all types of object-oriented code. The longer the code, the harder it becomes to understand and maintain it
  • Long code are great place to hide bugs and duplicated code, and we don’t want that, let’s keep the code as short as possible

Performance

  • The impact of additional code is not worth to worry about, it’s probably not even noticed significantly
  • With cleaner and understandable code, it’s easier to find non-performatic code and then apply performance techniques