Conditional clauses sometimes lead to code that is more difficult to manage. This includes not only the if
, but even more often the switch
, which usually includes more branches than the corresponding if
.
There are times when it is wise to use if
When you write helper methods, extensions, or specific library functions, it is likely that you will not be able to avoid if
(and should not). There is no better way to encode this little function and make it more documented than it is:
Branching over "type code" is the smell of code
On the other hand, if you come across code that checks some type code or checks to see if a variable is of a particular type, then this is most likely a good candidate for refactoring, namely replacing a conditional expression with polymorphism .
The reason for this is that by allowing your callers to jump to a certain type of code, you are able to end up with a lot of checks scattered throughout the code, which greatly complicates the expansion and maintenance. Polymorphism, on the other hand, allows you to make this decision about branching as close as possible to the root of your program.
To consider:
By placing common, but type-specific (that is, class-specific) functionality in separate classes and exposing them through a virtual method (or interface), you allow the internal parts of your program to delegate this solution to someone higher in the call hierarchy (potentially in one place in the code), which greatly simplifies testing (prototyping), extensibility and maintenance:
And now you can easily check if your RunVehicle
method RunVehicle
as follows:
Patterns that differ only if
conditions can be reused
Regarding the argument of replacing if
with a “predicate” in your question, Haines probably wanted to mention that sometimes there are similar patterns in your code that differ only in their conditional expressions. Conditional expressions appear along with if
s, but the whole idea is to extract the repeating pattern in a separate method, leaving the expression as a parameter. This is what LINQ is already doing, usually the result is cleaner code than alternative foreach
:
Consider these two very similar methods:
This means that you can extract the condition into the predicate, leaving you with one method for these two cases (and many other future cases):
And since LINQ already has many such convenient extension methods, you don’t even need to write your own methods:
In this latest version of LINQ, the if
completely “disappeared”, though:
- To be honest, the problem was not in the
if
itself, but in the entire code template (simply because it was duplicated), and if
still really exists, but it is written inside the LINQ Where
extension method, which has been tested and closed for modification. Having less code of your own is always good: fewer things to test, fewer errors, and code is easier to track, analyze and maintain.
Refactoring when you smell code, but don't overload
Having said all this, you should not spend sleepless nights on a couple of conventions from time to time. Although these answers may provide some general practical rules, the best way to be able to detect constructs that require refactoring is through experience. Over time, some patterns appear that lead to changes in the same sentences over and over again.