Rule 4. Generalization Takes Three Examples
We’re all taught as new programmers that general solutions are preferable to specific ones. Better to write one function that solves two problems than to write separate functions for each problem.
You’re unlikely to write this code:
Sign*findRedSign(constvector<Sign*>&signs){for(Sign*sign:signs)if(sign->color()==Color::Red)returnsign;returnnullptr;}
When it would be easy to write this code:
Sign*findSignByColor(constvector<Sign*>&signs,Colorcolor){for(Sign*sign:signs)if(sign->color()==color)returnsign;returnnullptr;}
It’s natural to think in terms of generalization, especially for such a simple example. If you need to find all the red signs in the world, your natural instinct as a programmer is to write the code to find signs of an arbitrary color, then pass in red as that color. Nature abhors a vacuum; programmers abhor code that only solves one problem.
It’s worth thinking about why this feels so natural. At some level, the instinct to write findSignByColor instead of findRedSign is based on a prediction. Given that you’re looking for a red sign, you can confidently predict that at some point you’ll want to look for a blue sign and write the code to handle that case too.
In fact, why stop there? Why not write an even more general solution for finding signs?
You could create a more general interface that lets you query any aspect of the sign—color, size, location, text—so that ...