Combinatorial Explosion

Sign of Smell

This smell occurs when multiple pieces of code achieve almost the same task but use different combinations of data or behavior.

If you catch up the keyword like “Doing the same thing in different ways”, you might doubt that it’s the same smell as “Duplicated Code” or “Oddball Solution”, but in fact, it’s a relative of Parallel Inheritance Hierarchies code smell, but everything has been folded into one hierarchy.

According to Marcel Jerzyk in his book "Code Smells: A Comprehensive Online Catalog and Taxonomy," both "Combinatorial Explosion" and "Oddball Solution" are categorized under Bloaters. However, in my opinion, I believe the “Combinatorial Explosion” smell belongs to the Change Preventers catalog instead. The key factor supporting my point is that when we modify one part, we also need to make simultaneous changes to another part when dealing with the Combinatorial Explosion code, and it exactly fits the definition of the Change Preventers catalog.

When comparing this smell to the Duplicated Code smell, the "Combinatorial Explosion" refers to repeated similar code caused by a parallel design, where it has to go through all possible combinations. On the other hand, Duplicated Code has similar code to solve the same or different tasks incidentally, not intentionally.

Additionally, when we compare it to the Oddball Solution smell, it's the smell that tries to solve the same problem in a different place using a different approach. The unnecessary difference and repetition make this code inconsistent. As a result, I believe it belongs in the Dispensables catalog.

Reason of Smell

  • Readability: Code with a high degree of combinatorial complexity can be difficult to read. Developers may struggle to understand the interactions between different data or behaviors, leading to reduced code quality.

  • Complexity: As the number of possible combinations of inputs or options increases, the code becomes more complex and harder to understand. This complexity can lead to bugs, difficult debugging, and increased maintenance costs.

  • Don’t Repeat Yourself Principle Violation: When a Combinatorial Explosion occurs, it often leads to code duplication because developers may write similar or identical logic to handle various combinations of options. This duplication not only violates the DRY principle but also makes the codebase more error-prone.

  • Open-Closed Principle Violation: The OCP is one of the SOLID principles of object-oriented design, and it emphasizes that software entities (e.g., classes, modules, functions) should be open for extension but closed for modification. Combinatorial Explosion can violate this principle when handling new combinations requires modifying existing code, leading to potential risks.

  • High Coupling: Combinatorial Complexity often indicates high coupling between different parts of codes. In fact, parallelism is an indication of coupling. It means that we have to perform the same changes as if it were a couple of codes.

  • Test Challenges: With a large number of combinations, testing all possible scenarios becomes impractical and time-consuming. This can result in inadequate testing, leading to undiscovered bugs.

Refactoring Recipes

There’s only one refactoring skill on the origin table, but I added other 2 skills that I think are also well-matched.

  • Replace Implicit Language with Interpreter

  • Replace Inheritance with Delegation

  • Move Embellishment to Decorator

Replace Implicit Language with Interpreter

"Implicit Language" refers to a set of logic or rules that are expressed indirectly and non-obviously. It may involve complex conditionals, decision flows, numerical calculations, and other elements. However, it lacks proper structuring, which makes it less immediately understandable.

The Interpreter is a design pattern that addresses problems by utilizing a Domain-Specific Language (DSL). This DSL represents configurations or combinations in a structured manner, following a defined grammar or set of rules.

To address the issue of Combinatorial Explosion, refactor your code by separating the configuration or combination logic from the core application logic. Instead of scattering complex conditional statements or configuration handling throughout your codebase, use an interpreter to evaluate and execute DSL expressions.

Replace Inheritance with Delegation

We can often solve this smell by replacing inheritance with delegation. This approach can help reduce complexity, improve code organization, and eliminate the need for Combinatorial Explosion.

In this refactoring technique, we can replace the Combinatorial Explosion with a composition-based approach. Instead of inheriting from a base class, we can delegate responsibilities to feature-specific objects. This allows for easy mixing and matching of different features.

Move Embellishment to Decorator

In object-oriented programming, sharing common logic among multiple classes is often done through "inheritance." However, inheritance has drawbacks. It is static, meaning we can't change an object's inheritance at runtime. Additionally, most languages only allow a class to inherit from one parent class. As subclasses share a common base class, they may only need a small portion of their functionality, resulting in unintended side effects.

The Decorator design pattern addresses the limitations of "inheritance" by offering a flexible approach to dynamically extend and share functionality, minimizing the dependency between subclasses and their parent classes. Unlike inheritance, which extends a single base class, the Decorator pattern allows decorators to better adhere to the Single Responsibility Principle by separating the core logic, structure, and additional features.

Reference

https://luzkan.github.io/smells/combinatorial-explosion

https://github.com/Luzkan/smells/blob/main/docs/thesis.pdf

Last updated