Hello there, my sweet fellow developers,
Sometimes you could write a code, that is not duplicated on the syntax level, but is duplicated logically. Lets take a look at a simple case:
1 2 3 4 5 6 7 8 |
func faultyEqualValues(_ value1: Int, _ value2: Int) -> Bool { if value1 == value2 { return true } else { return false } } |
Ultimately, this piece of code says: “if yes return yes, otherwise return no”. A weird accent, I could say. Lets rewrite it in a better way:
1 2 3 4 |
func equalValues(_ value1: Int, _ value2: Int) -> Bool { return value1 == value2 } |
You could tell, that noone would make such mistakes in real-life code and God, how wrong you are. Lets just extend that code a bit:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
func faultyDidProcessEqual(_ value1: Int, _ value2: Int) -> Bool { if value1 == value2 { let object = NSObject() // I know it's incorrect, but I'm too lazy print(object) // some sophisticated processing here return true } else { let value = value1 + 10 // I know it's incorrect, but I'm too lazy print(value * 100) // some sophisticated processing here return false } } |
Yeah, I’m sure, you’ve seen such a code. I’ve seen it so much times in different variations, I’d be unable to count them all. A better solution:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
func didProcessEqual(_ value1: Int, _ value2: Int) -> Bool { let isEqual = value1 == value2 if isEqual { let object = String(value1 + value2) // I know it's incorrect, but I'm too lazy print(object) // some sophisticated processing here } else { let value = value1 + 10 // I know it's incorrect, but I'm too lazy print(value * 100) // some sophisticated processing here } return isEqual } |
But the best solution, would actually be to decompose the task in a different manner, as it seems, the function does more. But I can’t paste the real – life code I have (NDA’s at their worst), and it would make little sense to try to redecompose didProcessEqual because of its obvious simplicity. But I’ll try. The obvious way of decomposition is to move the processing out of the function, but lets make an assumption, that part of the processing is similar for both cases of equality:
1 2 3 4 5 6 7 8 9 |
func faultyProcess(_ value1: Int, _ value2: Int) { if equalValues(1, 2) { calculateSomething() calculateABitMore() } else { calculateSomething() } } |
And yeah, you guessed it right. This solution yields us the duplication. And we try to avoid it. Moreover, in schools we learned, that 2 * a + 2 * b = 2 * (a + b). However, when we start coding, we seem to forget that simple principle. Lets try to apply it to the faultyProcess:
1 2 3 4 5 6 7 |
func process(_ value1: Int, _ value2: Int) { calculateSomething() if equalValues(1, 2) { calculateABitMore() } } |
Those are just the simple basics, but I’ve seen such code produced by young devs with less, than 1 year of experience, as well as by devs with 8 years of experience.
As an afterword, be DRY and review your code for such mistakes. Kudos and pats on your back, if you didn’t do that or at least would avoid doing that in the future.
That’s all, folks. Have a great day and stay DRY, no matter, where you are.