Categories
Projects

Code Smells To Be Aware of In Code Reviews

“Code smells” are what you detect when you have a “WTF” moment as you review code. Early in your software development career, you may get a negative feeling, like a “Spidey Sense,” that something in the code is wrong, but you might not be able to articulate the exact problem. Most of these problems can be described as “code smells.” If you are aware of common code smells, it can give you a good idea of what’s wrong and what to change.

Rigidity: Code that is difficult to change because it is too tightly coupled.

Causes:

  • Inappropriate use of inheritance or subclassing
  • Overuse of global variables
  • Over-reliance on low-level details
  • Tight coupling between modules or classes

Remedies:

  • Use interfaces to decouple components
  • Refactor code to use composition instead of inheritance
  • Use dependency injection to reduce coupling between modules
  • Use design patterns like the Observer or Strategy patterns to reduce tight coupling

Needless Complexity: Code that is overly complicated and difficult to understand.

Causes:

  • Over-engineering or over-architecting
  • Lack of clarity in the code
  • Complex conditional statements
  • Long methods or classes

Remedies:

  • Simplify the code by removing unnecessary features
  • Break up long methods into smaller, more manageable ones
  • Simplify complex conditional statements using boolean algebra or the Strategy pattern
  • Use meaningful variable and method names to improve code clarity

Duplicated Code: Code that is repeated multiple times within the same codebase.

Causes:

  • Lack of code reuse
  • Copy-pasting code
  • Insufficient refactoring

Remedies:

  • Use inheritance, composition, or interfaces to promote code reuse
  • Extract common functionality into separate methods or classes
  • Use a code refactoring tool to identify and eliminate duplicate code
  • Use code templates or snippets to avoid copy-pasting

Fragility: A codebase that is overly sensitive to changes in other parts of the system, leading to bugs and unintended consequences.

Causes:

  • Tight coupling between different parts of the system
  • Violation of the Open-Closed Principle
  • Inadequate encapsulation

Remedies:

  • Use interfaces to promote loose coupling and reduce dependencies
  • Use dependency injection to promote modularity and reduce coupling
  • Use design patterns like the Observer or Mediator patterns to decouple different parts of the system
  • Use automated tests to catch regressions and ensure that changes don’t introduce new bugs

By addressing fragility in a codebase, developers can make it more robust and easier to work with, even as the system evolves and changes over time.

Shotgun Surgery: Changes to one part of the codebase that require changes to multiple other parts.

Causes:

  • Tight coupling between different modules or classes
  • Insufficient modularity or abstraction
  • Lack of clear separation of concerns

Remedies:

  • Use interfaces or dependency injection to reduce coupling
  • Use design patterns like the Observer or Mediator patterns to reduce tight coupling
  • Refactor the codebase to promote modularity and abstraction
  • Use the Single Responsibility Principle to ensure clear separation of concerns

Feature Envy: A class that uses methods or data of another class more than its own.

Causes:

  • Insufficient encapsulation
  • Inappropriate use of inheritance or subclassing
  • Tight coupling between different classes or modules

Remedies:

  • Refactor the code to promote encapsulation and reduce coupling
  • Use interfaces to decouple components
  • Use composition instead of inheritance where appropriate
  • Use the Law of Demeter to ensure that classes only use methods and data of objects they directly depend on

Large Class: A class that has become too large and difficult to understand or maintain.

Causes:

  • Violation of the Single Responsibility Principle
  • Inadequate encapsulation
  • Insufficient modularity

Remedies:

  • Break up the class into smaller, more manageable classes
  • Use composition instead of inheritance to promote modularity
  • Use interfaces to promote encapsulation and reduce coupling
  • Use design patterns like the Facade or Adapter patterns to simplify complex interactions

Long Method: A method that has become too long and difficult to understand or maintain.

Causes:

  • Inadequate encapsulation
  • Violation of the Single Responsibility Principle
  • Insufficient modularity

Remedies:

  • Break up the method into smaller, more manageable methods
  • Use interfaces to promote encapsulation and reduce coupling
  • Use composition instead of inheritance to promote modularity
  • Use design patterns like the Template Method pattern to promote code reuse

Data Clumps: Multiple data items that are frequently used together, but not grouped into a single object.

Causes:

  • Insufficient modularity
  • Lack of abstraction
  • Poor design

Remedies:

  • Group related data items into a single object
  • Use design patterns like the Composite or Visitor patterns to promote modularity and abstraction
  • Use composition instead of inheritance to promote code reuse and modularity

Primitive Obsession: Overuse of primitive types (like strings or integers) instead of creating custom objects to represent concepts.

Causes:

  • Insufficient abstraction
  • Lack of clarity in the code
  • Poor design

Remedies:

  • Create custom objects to represent concepts instead of using primitive types
  • Use interfaces to promote modularity and abstraction
  • Use design patterns like the Builder or Factory patterns to create custom objects
  • Use meaningful variable and method names to improve code clarity

Switch Statements: Overuse of switch statements, which can make code difficult to understand and maintain.

Causes:

  • Poor design
  • Insufficient modularity
  • Lack of abstraction

Remedies:

  • Use polymorphism instead of switch statements to promote modularity and abstraction
  • Use design patterns like the Strategy or State patterns to avoid switch statements
  • Use meaningful variable and method names to improve code clarity

Leave a Reply

Your email address will not be published.