Conditionals Expressions Considered Harmful
Use a Factory instead.
How much simpler can code get than a humble if/else statement or a casual ternary expression?
I learned the answer to that question myself from Sandi Metz (youtube). In the linked talk, Metz shares some example code in Ruby, where she starts with code containing 4 boolean conditionals resulting in 16 possible code paths. To test that code, I will need 16 tests. Instead, Metz goes on to refactor the code, hiding the conditional expressions in a Factory class. In the resulting code, there is only 1 code path in each of the 5 non-factory objects. I have nearly twice as much code, but each object is completely independent and has a single responsibility.
Metz is a Ruby girl, but I wanted to reproduce this learning for myself in a language I am more familiar with. I usually work in JS/TS/C#/C++, and I chose C#/dotnet for this exercise.
I started with the following code. I have omitted some defensive code validating the arguments, and etcetera. I never tested this code, so please excuse errors you may encounter, the correctness of the code is not the point. You can probably follow the code fairly easily, it's not that complicated. It counts the number of rows in a CSV or Excel spreadsheet, and prints that count to the console.
There are three code paths here. Two happy paths, one sad path.
The first thing that Metz suggests is to isolate the things that I want to change in an object.
I take the CSV-specific code and put it in a dedicated class.
领英推荐
I should inject Console as a dependency, but to keep this article focused I will not do that just now.
I won't show you the ExcelTableReader, you already have a good idea what that looks like.
Now Metz tells me to hide my conditional in a Factory. Here it is.
Finally, my main function is now simply this:
I have done more than merely break my logic into smaller pieces. I've reduced the number of code paths in my actual code. My Main function only has one code path. Each TableReader implementation has only one code path. The TableReaderFactory still has three code paths, but the conditional expression is the only thing it has. It has only one responsibility. And that means the system as a whole is much easier to understand than the original code. That's a win.
Sandi Metz is one of my favourite conference speakers, if you enjoyed this little nugget, I encourage you to look her up on Youtube, she has a lot of valuable ideas to share.
Further Reading