Refactoring If statements
Background
Recently, I reviewed one of my peer’s code that involved lots of if/branching statements. To my surprise, the code block that had only if statements were about 50 lines. And that got me thinking what are different ways through which we can avoid nested branching & make our code more readable and maintainable.
The Code
Let’s see the code snippet that had nested branching, which we will use to refactor through different options available to us.
If you closely read the DrawTable method, you’ll find that there are only 6 conditions that code is trying to handle and do something different depending upon the condition. And those 6 conditions are again used by DrawRow method. The problem in the above code snippet is twofold. Firstly, it contains nested branching and secondly, the same conditions are getting repeated to do achieve some another functionality. If business logic gets changed then we do need to update conditions in both methods, column creation as well as row creation logic. Obviously, the code is hard to read and much harder to maintain.
Road to redemption
So, what different options we have, to refactor the above code?
C# 8 Pattern matching
Well, I know one and it’s one of the C# 8 coolest feature i.e. pattern matching. I hope you also have heard about it. Let’s use that to refactor our nested branching.
How cool was that? I mean those 6 conditions got covered in 6 lines. I agree, we had to tweak a little bit to return an Action in DrawColumsWithTuples method to use the new syntax but that not only simplified our code but also made easier to see those business conditions. If you want to learn more about pattern matching see microsoft docs: https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/pattern-matching.
Did it solve our complete problem? To be completely honest “no” it hasn’t. We still have to maintain conditions in two methods and what about if we are not using latest C# 8 in our codebase.
So, pattern matching solves our problem but only if we have C# 8. Let’s look out for some more options.
Breaking conditions in smaller methods
In this approach we will break our 6 business conditions into 6 different methods and call them to evaluate necessary action to be taken by DrawColumns and DrawRow methods.
Using this approach we have centralized our business rules & have reduced nested branching. But downside to this is that we have introduced few more ifs statements to know which action needs to be performed.
Strategy Pattern
One of the very common design pattern used to handle different behaviors based on the strategy or rule.
In this approach, we will create 6 separate classes for handling 6 different business rules that we have. We can then create a dictionary to decide which class’s methods need to be invoked. With this approach we will eliminate all if statements and replace them by dictionary key in form C# tuple.
Of course, we can create a separate class to keep our dictionary and object creation logic say RuleContext or something. But in here I just kept the code simpler.
Conclusion
There are various ways through which we can keep our code simpler and maintainable. The important point is we should write our code in such a manner that a piece of code should do one only thing(SRP). And nested branching makes it difficult to read and maintain, so whenever we come across such code we should re-think about the design.