Yes, if you take them as general guidelines, not dogmatic rules with variable interpretations
The latter is exactly what his fans do
> 2 .Keep it simple stupid
> 2. Prefer polymorphism to if/else or switch/case.
No, not at odds with one another...
Yes, if you take them as general guidelines, not dogmatic rules with variable interpretations
The latter is exactly what his fans do
> 2 .Keep it simple stupid
> 2. Prefer polymorphism to if/else or switch/case.
No, not at odds with one another...
Whatever approach is clean or not can vary wildly by language. Or framework.
I do like clean code, but I think the article has a point: it's a very vague concept.
Suppose the program has to make a choice. When the choice exists only in 1 place, use an if/switch. When the choice exists in multiple places, polymorphism centralizes it and quickly becomes the simple option.
For example, a change in law required us to make a choice based on a date:
If (thing.someBusinessDate < 2010-06-01) { doTheOldWay();} else{doTheNewWay();}
after a while, a few edge cases sprang up, and we got variants of this code hiding in multiple corners. Then the law changed again with a new cutoff date. So we adapted to polymorphism: interface TheWay{ edgecase1(); edgecase2();...}
class TheOldWay implements TheWay{...}
class TheNewWay implements TheWay{...}
class TheNewNewWay implements TheWay{...}
TheWay wayDetector(thing){/* all the ifs here */}
Unfortunately, adding just one more 'if' was always the cheapest choice. The refactoring was nevertheless clearly a better choice: it enabled us to point out more forgotten edge cases, avoiding costly mistakes.That said, I think "simple" if/else or switches are much more common than the complex cases that fit polymorphism, so it seems a bit off to have it as a general rule to prefer polymorphism.
And notice how if one needs to add a new action, all objects are required to implement it. In typical OOP languages that touches many files even if the action is used only once.
So polymorphism works nicely if there are only few actions but many different objects, like in a typical GUI. But in cases of few objects and many actions, for example, doing a lot of different queries over few data sets it leads to a lot of boilerplate. Switch over actions will lead to less code.
Cyclomatic complexity would put if/else behind polymorphism while using lines of code and depth of inheritance would favour the if/else way.
That's the crux with software - there's not always an objectively better solution in terms readability/comprehensibility and some metrics that try to capture these qualities are inherently at odds with each other.
- you have the same if-then-else in 3 places in code with 3 different effects
- you refactor it to polimorphism (Enum with a few overloaded methods works well in java)
- now one of these places need additional condition so you make it a little more complex
- year passes
- you have eldritch abomination of OOP instead of 3 if-then-elses with slightly different conditions because at no point someone was brave enough to refactor back into if-then-elses as the special cases piled up
It has benefits, if you do not apply it dogmatically everywhere