Code Smell | Shotgun Surgery

Code Smell | Shotgun Surgery

March 16, 2022

codequality
refactorit
code-smell

Hello, today we are back with the code smells refactoring series and in this case we are going to talk about code smell called Shotgun Surgery, this smell can be detected if making a change have to replicate this change in different parts of our code


Cause

A single responsibility has been split up among a large number of sites. This can happen after the overzealous application of Divergent Change


Example

We can see that the minimum balance check is being duplicated in both methods

class Account {
    private amount: number
 
    constructor(amount: number) {
        this.amount = amount
 
        //...
    }
 
    debit(debitAmount: number): void {
        if (this.amount <= 1000) {
            throw new Error('Minimum balance should be over 1000')
        }
 
        //...
    }
 
    transfer(from: Account, to: Account, transferAmount: number): void {
        if (from.amount <= 1000) {
            throw new Error('Minimum balance should be over 1000')
        }
 
        //...
    }
}

Solution

Extract minimum balance checks to method to be able to reuse it in the different methods of the class

class Account {
    private amount: number
 
    constructor(amount: number) {
        this.amount = amount
 
        //...
    }
 
    assertMinimumBalance(amount: number): void {
        const MINIMUM_AMOUNT = 1000
 
        if (amount <= MINIMUM_AMOUNT) {
            throw new Error(`Minimum balance should be over ${MINIMUM_AMOUNT}`)
        }
    }
 
    debit(debitAmount: number): void {
        this.assertMinimumBalance(this.amount)
 
        //...
    }
 
    transfer(from: Account, to: Account, transferAmount: number): void {
        this.assertMinimumBalance(from.amount)
 
        //...
    }
}

Bonus track

Shotgun surgery in CSS? 🤔

Yes, see the next example:

.button-primary {
    background-color: #ec407a;
}
 
.button-secondary {
    background-color: #b4004e;
}
 
.navbar-primary {
    background-color: #ec407a;
}
 
.navbar-secondary {
    background-color: #b4004e;
}

If now they ask us to modify the primary color for another, what is the solution? Search globally in all our CSS and replace it? NOOO!! ⛔️

The solution is use CSS variables:

We can declare variables in CSS globally with the pseudo-class :root and thus use them in any part of our CSS, in this way we centralize the possible changes in only the variables, thus avoiding having to replace each color value

:root {
    --primary-background: #ec407a;
    --secondary-background: #b4004e;
}
 
.button-primary {
    background-color: var(--primary-background);
}
 
.button-secondary {
    background-color: var(--secondary-background);
}
 
.navbar-primary {
    background-color: var(--primary-background);
}
 
.navbar-secondary {
    background-color: var(--secondary-background);
}

Thanks for reading me 😊