Tipically, when you start to learn to code, one of the first concepts that you learn is to modularize, even before learning what a module is. Normally when you learn to create functions a teacher will tell you something like "you should do this when you see repeated code" which is not necessarily wrong, but it's incomplete. The problem is that everyone starts doing it for that reason only. And usually leads to ugly code, which is less readable, which is less maintainable; and as we know Maintainability is the key to a healthy project.
I propose you to forget about reutilization and start thinking in terms of code readability. I'm not saying don't reuse, but for the sake of argument lets pretend that's not an option for now.
Imagine that you have some if
statement where the condition is not too complex but not too simple either.
Take a look at the following code:
bool isLeapYear(int year){
if( ( year % 4 ) != 0 ) {
return false;
} else if ( (year % 400) == 0 ) {
return true;
} else if ( ( year % 100 ) == 0 ){
return false;
} else {
return true;
}
}
It's a simple leap year checker; but still that code forces you to analyze it in order to understand it. Let's try to separate the abstraction levels.
bool isLeapYear(int year){
if( !isDivisibleBy(year, 4) ) {
return false;
} else if ( isDivisibleBy(year, 400) ) {
return true;
} else if ( isDivisibleBy(year, 100) ){
return false;
} else {
return true;
}
}
bool isDivisibleBy(int year, int divisor){
return ( year % divisor ) == 0;
}
Which could lead to an even simpler solution:
bool isLeapYear(int year){
return isDivisibleBy(year, 400) ||
( isDivisibleBy(year, 4) && !isDivisibleBy(year, 100) );
}
And if you are working on a language that supports extensions you can do something like this:
extension LeapYearExtension on int {
bool isDivisibleBy(int divisor) {
return (this % divisor) == 0;
}
bool isLeapYear() {
return isDivisibleBy(400) ||
( isDivisibleBy(4) && !isDivisibleBy(100) );
}
}
2023.isLeapYear() // false
A function that evaluates if a given year is a leap year doesn't need to know about how to calculate if a number is divisible by other or if a number is a multiple of other; it just delegates that logic to another function.
The same way, no function should handle lower – or higher – level logic that it's own.
Having this in mind, the next time you code something, try to extract methods to declare abstraction levels, no just code reuse.
Thanks for reading.