Conditional Complexity — Code Smells Catalog Skip to content

Conditional Complexity

Also known as: Repeated Switching, Switch Statement, Conditional Complexity, Prefer Polymorphism to if/else or switch/case

Object Oriented Abusers Conditional Logic Code SmellDesign SmellImplementation Smell Within Class

The if/else chain that grows a new branch with every feature. First it's readable. Then it's manageable. Then it's a 200-line switch statement, and suddenly the polymorphism refactor everyone...

4 min read 3 sources

Overview

In data-oriented programming, the usage of switch-like statements (lengthy, cascading if statements or switch/case) should be relatively rare. One such switch usually executes code scattered around the code base and should usually be replaced with a polymorphism solution.

This smell was phrased initially as Switch Statement by Fowler and Beck back in 1999 [1]. One year later, Mäntylä noted that such a name is misleading since switch statements do not necessarily imply a code smell but rather just in the situation when they are used instead of a viable polymorphism solution. [2] Fowler, 14 years later, in his newest book in 2018, changed the name, suggesting Repeated Switching, agreeing that, fortuitously due to the way he initially phrased it, conditional statements got a bad reputation, while he never unconditionally opposed the existence of all if-s and switch-es. [3] In the “Clean Code” by Robert Martin, the smell was called “Prefer Polymorphism to if/else or switch/case”, which is lengthy, but it hits the nail on the head. [4]

I provide a typical example of this issue on an Exporter class with different file formats. A new elif has been added for each new feature instead of using an Object-Oriented solution like the Factory Method.

Keeping a class focused on a single concern is vital to make it more robust. Martin Fowler defines responsibility as a reason to change, concluding that “A class should have only one reason to change.” [3]. An example that violates this would be a class that prints a table that handles both the contents of the cells and the styling of the table.

Another situation, which is not explicitly mentioned in the sources, would be a nested Try and Except/Catch “checklist”, where numerous error-catching blocks are used instead of one generalized for the situation at hand.

Causation

The most common way such a smell can be created is when a conditional switch behavior is used instead of creating a new class. The first time it happens is not yet a “scent-ish” smell, but this immediately becomes a saturated red flag as soon as it is done the second time [5]. Logic blocks grew over time more extensive, and no one bothered to implement an Object-Oriented Programming style alternative like decorator, strategy, or state. It was easier to add another else if.

Problems

Open-Closed Principle Violation

The class should be open for extension but closed for modification

🧩
More Complex APIs
📖
Comprehensibility

If statement blocks make things harder to understand as they require to think about all the possible paths the logic can go.

🔀
Unnecessary Indirection

Most likely, there is a way to execute one method on a polymorphic class instead of switching cases.

🧩
Increased Test Complexity

Each subsequent if branch needs each subsequent test.

Example

1class Exporter:
2    def export(self, export_format: str):
3        if export_format == 'wav':
4            self.exportInWav()
5        elif export_format == 'flac':
6            self.exportInFlac()
7        elif export_format == 'mp3':
8            self.exportInMp3()
9        elif export_format == 'ogg':
10            self.exportInOgg()
PYTHON

Refactoring

  • Use a Guard Clause
  • Extract Conditional
  • Replace with Polymorphism
  • Use Strategy Pattern
  • Use Null Object
  • Use Functional Programming Based Solution

Sources

Browse All 56 Smells