Exploring Code Smells: Identifying and Solving Common Issues
Tags: refactoring, php, oops, codesmell
Published: 2023-11-16 10:22:00

---
title: Exploring Code Smells: Identifying and Solving Common Issues
published: true
description: In software development, maintaining a clean and efficient codebase is crucial. Recognizing code smells, which are warning signs indicating potential problems in your code, is an essential skill. While they don't directly affect the functioning of the program, they can make the code harder to maintain and extend. Let's delve into the first five common code smells, understand their implications, and explore ways to resolve them, with examples for better clarity.
tags: refactoring, php, oops, codesmell
canonical_url: https://akhil.se/exploring-code-smells-identifying-and-solving-common-issues
cover_image: https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/wQLAGv4_OYs/upload/e57fe25efee631e72643be5515f4c7b5.jpeg
# Use a ratio of 100:42 for best results.
published_at: 2023-11-16 11:22 +0100
---

### Understanding Code Smell and Its Types with Examples

In software development, maintaining a clean and efficient codebase is crucial. Recognizing code smells, which are warning signs indicating potential problems in your code, is an essential skill. While they don't directly affect the functioning of the program, they can make the code harder to maintain and extend. Let's delve into the first five common code smells, understand their implications, and explore ways to resolve them, with examples for better clarity.

#### 1\. **Long Method**

The 'Long Method' smell occurs when a method in a program becomes too lengthy, containing too many lines of code. This often happens when the method is handling too many responsibilities.

**Problem**: Long methods are hard to read, understand, and debug. They often contain duplicate code and make it challenging to identify and fix bugs.

**Example**:

```php
function processOrder($order) {
    // Check inventory
    // Update order status
    // Calculate shipping cost
    // Apply discounts
    // Validate payment information
    // Send notification
    // Dozens of lines handling various aspects of order processing
}
```

In this example, `processOrder` does multiple things, making it a complex method to understand and modify.

**Solution**: The solution is to break the method into smaller, more focused methods. This practice is known as method decomposition.

```php
function checkInventory($order) { /* ... */ }
function updateOrderStatus($order, $status) { /* ... */ }
function calculateShippingCost($order) { /* ... */ }
// More such focused methods
```

By breaking the long method into smaller methods, each with a single responsibility, the code becomes cleaner, easier to maintain, and less prone to errors.

#### 2\. **Large Class**

A 'Large Class' is a class that tries to do too much. It often contains too many fields, methods, and lines of code.

**Problem**: Large classes are challenging to understand and maintain. They often violate the Single Responsibility Principle (SRP), leading to a higher chance of bugs and difficulties in testing.

**Example**:

```php
class OrderManager {
    // Fields for order processing, customer details, payment, notifications
    // Methods for each of these aspects
    // Hundreds of lines of code
}
```

In this case, `OrderManager` is doing more than managing orders; it's handling multiple unrelated responsibilities.

**Solution**: The key is to apply SRP and break the class into smaller classes, each handling a single responsibility.

```php
class OrderProcessor { /* ... */ }
class CustomerManager { /* ... */ }
class PaymentHandler { /* ... */ }
class NotificationSender { /* ... */ }
```

Refactoring the large class into several smaller classes makes the code more modular, easier to understand, and simplifies future modifications.

#### 3\. **Primitive Obsession**

Primitive Obsession refers to the overuse of primitive data types instead of small objects for simple tasks.

**Problem**: It can lead to duplication, lack of expressiveness, and increased error potential. For instance, using raw strings or numbers for complex data like currency, phone numbers, or date ranges can be problematic.

**Example**:

```php
function createInvoice($date, $amount, $currency) {
    // Uses primitives for date and currency
}
```

Here, `$date` and `$currency` are likely to be strings or numbers, which are not expressive and prone to errors.

**Solution**: Replace primitives with small objects that have a specific role.

```php
class Date {
    private $date;
    // Constructor and methods
}

class Currency {
    private $currency;
    // Constructor and methods
}

function createInvoice(Date $date, Amount $amount, Currency $currency) { /* ... */ }
```

By using specific classes, the code becomes more readable, maintainable, and less prone to common mistakes.

#### 4\. **Long Parameter List**

Methods with long lists of parameters can be confusing and hard to use.

**Problem**: They make method calls difficult to read and understand, especially when multiple parameters are of the same type. This can also lead to errors, such as parameters being passed in the wrong order.

**Example**:

```php
function createReport($startDate, $endDate, $user, $format, $includeImages, $pageSize, $orientation) {
    // Complex method with many parameters
}
```

In this example, understanding what each parameter represents is challenging, and calling this method can be error-prone.

**Solution**: Encapsulate the parameters in an object.

```php
class ReportConfig {
    private $startDate;
    private $endDate;
    // Other fields

    // Constructor and methods
}

function createReport(ReportConfig $config) { /* ... */ }
```

Using a parameter object improves readability and makes the method call simpler and less error-prone.

#### 5\. **Data Clumps**

Data clumps occur when the same group of data fields (like parameters, variables) repeatedly appear together in multiple classes or methods.

**Problem**: This repetition is a sign that the data belongs together and should be encapsulated in its own object. It makes the code less maintainable and increases the risk of inconsistencies.

**Example**:

```php
function calculateShippingCost($width, $height, $depth, $weight) { /* ... */ }
function calculatePackageVolume($width, $height, $depth) { /* ... */ }
```

In these functions, the parameters `$width`, `$height`, and `$depth` repeatedly appear together.

**Solution**: Group these fields into a class.

```php
class Package {
    private $width;
    private $height;
    private $depth;
    private $weight;

    // Constructor and methods
}

function calculateShippingCost(Package $package) { /* ... */ }
function calculatePackageVolume(Package $package) { /* ... */ }
```

Encapsulating the related data into a `Package` class reduces duplication and makes the functions cleaner and more consistent.

#### 6\. **Switch Statements**

Using excessive switch or if statements, especially when dealing with different types or actions, can be a sign of trouble.

**Problem**: Such statements are hard to manage and extend. They often violate the Open-Closed Principle, as adding a new type or action requires modifying the existing switch statement.

**Example**:

```php
function calculatePay($employee) {
    switch ($employee->getType()) {
        case 'Manager':
            // Calculate pay for Manager
            break;
        case 'Worker':
            // Calculate pay for Worker
            break;
        // More cases
    }
}
```

Here, adding a new employee type requires changes to the `calculatePay` function.

**Solution**: Use polymorphism, allowing each type to have its own implementation of a method.

```php
abstract class Employee {
    abstract function calculatePay();
}

class Manager extends Employee {
    function calculatePay() { /* ... */ }
}

class Worker extends Employee {
    function calculatePay() { /* ... */ }
}
```

By using polymorphism, the code becomes more manageable and adheres to the Open-Closed Principle.

#### 7\. **Temporary Field**

Temporary fields are instance variables that are only set in certain situations.

**Problem**: They make the class's state inconsistent and the code difficult to understand, as the fields are not always relevant.

**Example**:

```php
class ReportGenerator {
    private $data;
    private $temporaryResult; // Set only in specific conditions

    function generateReport() {
        // Uses temporaryResult in some scenarios
    }
}
```

In this scenario, `temporaryResult` is not always used, making the class's state unpredictable.

**Solution**: Restructure the class to avoid temporary fields.

```php
class ReportGenerator {
    private $data;

    function generateReport() {
        $temporaryResult = $this->calculateTemporaryResult();
        // Use $temporaryResult
    }

    private function calculateTemporaryResult() {
        // Calculate and return the result
    }
}
```

This approach ensures the state of the class is consistent and clear.

#### 8\. **Refused Bequest**

This smell occurs when a subclass does not use inherited methods and properties from its parent class.

**Problem**: It indicates inappropriate inheritance, where the subclass and the superclass are not truly in a 'is-a' relationship.

**Example**:

```php
class Bird {
    function fly() { /* ... */ }
}

class Ostrich extends Bird {
    // Ostrich doesn't fly
}
```

Here, `Ostrich` inherits `fly` but doesn't use it, which is misleading.

**Solution**: Rethink the inheritance structure.

```php
class Bird { /* Common bird properties */ }

class FlyingBird extends Bird {
    function fly() { /* ... */ }
}

class Ostrich extends Bird { /* ... */ }
```

This approach correctly models the relationship between the classes.

#### 9\. **Alternative Classes with Different Interfaces**

This smell occurs when two classes do the same thing but with different method names.

**Problem**: It makes the code harder to understand and maintain, as the same concept is represented in different ways.

**Example**:

```php
class CSVReader {
    function readCSV() { /* ... */ }
}

class XMLReader {
    function loadXML() { /* ... */ }
}
```

Both classes perform similar operations but with different method names.

**Solution**: Standardize the interface or create a common interface.

```php
interface FileReader {
    function read();
}

class CSVReader implements FileReader {
    function read() { /* ... */ }
}

class XMLReader implements FileReader {
    function read() { /* ... */ }
}
```

By creating a common interface, the code becomes more uniform and easier to use.

#### 10\. **Parallel Inheritance Hierarchies**

This happens when you create a subclass in one class hierarchy, and as a result, you need to create a subclass in another.

**Problem**: It leads to tight coupling between the hierarchies, making the code harder to maintain.

**Example**:

```php
class User {}
class UserValidator {}

class Admin extends User {}
class AdminValidator extends UserValidator {}
```

Here, for every new `User` type, a new `Validator` type is needed.

**Solution**: Combine the hierarchies or use delegation.

```php
class User {
    private $validator;

    function __construct(UserValidator $validator) {
        $this->validator = $validator;
    }
}

class Admin extends User { /* ... */ }
```

With this approach, you avoid parallel inheritance and reduce coupling.

#### 11\. **Lazy Class**

A 'Lazy Class' refers to a class that does very little and doesn't justify its existence. It’s like having a tool that you hardly ever use.

**Problem**: These classes add unnecessary complexity to the codebase, making it harder to maintain.

**Example**:

```php
class Name {
    private $name;

    function getName() {
        return $this->name;
    }
}
```

Here, the `Name` class is overly simplistic and doesn't add much value.

**Solution**: Consider eliminating the class and using simpler data structures.

```php
// Instead of using a Name class, use a simple string variable
$name = "John Doe";
```

By replacing the class with a basic data type, the code becomes more straightforward and less bloated.

#### 12\. **Speculative Generality**

'Speculative Generality' occurs when code is added to support anticipated future features that never get used.

**Problem**: This leads to unnecessary complexity and code that is harder to understand and maintain.

**Example**:

```php
class FileManager {
    function read() { /* ... */ }
    function write() { /* ... */ }
    function compress() { /* Never used */ }
}
```

In this case, the `compress` method is never used and adds to the complexity.

**Solution**: Remove or comment out the unused code.

```php
class FileManager {
    function read() { /* ... */ }
    function write() { /* ... */ }
    // Removed unused compress method
}
```

Removing speculative features simplifies the code and focuses on current functionality.

#### 13\. **Feature Envy**

A method suffering from 'Feature Envy' is more interested in a class other than the one it resides in.

**Problem**: This smell indicates poor distribution of responsibilities and often leads to tightly coupled classes.

**Example**:

```php
class Order {
    private $total;

    function getTotal() {
        return $this->total;
    }
}

class Report {
    function generateOrderReport(Order $order) {
        $total = $order->getTotal();
        // Extensively uses Order's data
    }
}
```

Here, `generateOrderReport` in `Report` is more concerned with `Order` than `Report`.

**Solution**: Move the envious method to the class it envies.

```php
class Order {
    private $total;

    function getTotal() {
        return $this->total;
    }

    function generateReport() {
        // Generate report based on Order's data
    }
}
```

By relocating the method, the responsibilities are more logically distributed.

#### 14\. **Inappropriate Intimacy**

When one class knows too much about the internals of another class, it's considered 'Inappropriately Intimate'.

**Problem**: This breaks encapsulation and makes classes tightly coupled, leading to a fragile code structure.

**Example**:

```php
class Order {
    public $orderNumber;
    // Other public fields
}

class OrderProcessor {
    function process(Order $order) {
        echo $order->orderNumber;
        // Directly accesses Order's fields
    }
}
```

In this example, `OrderProcessor` directly accesses `Order`'s internal fields.

**Solution**: Use getter methods or rethink the design to reduce coupling.

```php
class Order {
    private $orderNumber;

    function getOrderNumber() {
        return $this->orderNumber;
    }
}

class OrderProcessor {
    function process(Order $order) {
        echo $order->getOrderNumber();
    }
}
```

Using getters and setters maintains encapsulation and reduces dependencies between classes.

#### 15\. **Message Chains**

A 'Message Chain' is a long chain of method calls, often navigating an object graph to perform operations.

**Problem**: These chains create tight coupling between the client and the intermediate objects. A change in any intermediate link can break the entire chain.

**Example**:

```php
echo $order->getCustomer()->getAccount()->getBillingAddress()->getZipCode();
```

Here, a simple operation requires navigating through multiple objects.

**Solution**: Apply the Law of Demeter to refactor the code, reducing dependencies.

```php
class Order {
    function getBillingZipCode() {
        return $this->getCustomer()->getAccount()->getBillingAddress()->getZipCode();
    }
}

echo $order->getBillingZipCode();
```

By providing a method in `Order` that hides the chain, the code becomes more robust and less prone to breakage from changes in the object graph.

#### 16\. **Middle Man**

A 'Middle Man' is a class that does little else than delegating work to other classes.

**Problem**: These classes increase complexity without adding significant value, making the code harder to navigate.

**Example**:

```php
class OrderController {
    private $orderService;

    function processOrder($data) {
        return $this->orderService->processOrder($data);
    }
}
```

Here, `OrderController` merely delegates the call to `OrderService`, adding an unnecessary layer.

**Solution**: Remove the middle man and interact directly with the service.

```php
// Directly use OrderService in the client code
$orderService = new OrderService();
$orderService->processOrder($data);
```

By eliminating the intermediary, the code becomes more straightforward and easier to understand.

#### 17\. **Insider Trading**

This smell occurs when classes have an intimate knowledge of each other’s internals, breaking encapsulation.

**Problem**: It creates a tightly coupled system, where changes in one class can have far-reaching effects on others.

**Example**:

```php
class Order {
    private $data;

    function processData() {
        // Process data
    }
}

class OrderProcessor {
    function process(Order $order) {
        $order->data = // Modify data directly
        $order->processData();
    }
}
```

`OrderProcessor` directly manipulates `Order`'s private data, indicating a high level of coupling.

**Solution**: Use public methods for interaction and maintain encapsulation.

```php
class Order {
    private $data;

    function setData($data) {
        $this->data = $data;
    }

    function processData() {
        // Process data
    }
}

class OrderProcessor {
    function process(Order $order) {
        $order->setData(/* new data */);
        $order->processData();
    }
}
```

Encapsulation is preserved, reducing the risk of unintended side-effects from external manipulation.

#### 18\. **Large Class (God Object)**

A 'Large Class', often called a 'God Object', knows too much or does too much, centralizing the functionality of a system.

**Problem**: It violates the Single Responsibility Principle, making the class difficult to understand, maintain, and extend.

**Example**:

```php
class Application {
    // Methods for user management, order processing, logging, notifications, etc.
}
```

This `Application` class is overloaded with responsibilities.

**Solution**: Break the class into smaller, focused classes.

```php
class UserManager { /* ... */ }
class OrderProcessor { /* ... */ }
class Logger { /* ... */ }
class NotificationService { /* ... */ }
```

By distributing responsibilities, the system becomes more modular and maintainable.

#### 19\. **Divergent Change**

Divergent Change occurs when one class is commonly changed in different ways for different reasons.

**Problem**: A single class undergoing changes for various unrelated reasons becomes hard to maintain and understand.

**Example**:

```php
class ReportGenerator {
    function generateCSVReport() { /* ... */ }
    function generatePDFReport() { /* ... */ }
}
```

Modifications in report generation (CSV or PDF) involve changing the `ReportGenerator` class.

**Solution**: Separate responsibilities into different classes.

```php
class CSVReportGenerator { function generate() { /* ... */ } }
class PDFReportGenerator { function generate() { /* ... */ } }
```

Separating concerns reduces the complexity and makes each class more focused and easier to maintain.

#### 20\. **Shotgun Surgery**

'Shotgun Surgery' is similar to divergent change but in reverse. It occurs when a change in one part of the system results in many small changes in various other parts.

**Problem**: The codebase becomes fragile, as changes are scattered across multiple locations.

**Example**:

```php
// Changing database schema affects multiple classes
class UserManager { /* ... */ }
class OrderManager { /* ... */ }
class InventoryManager { /* ... */ }
```

A database schema change requires modifications in several manager classes.

**Solution**: Centralize the change-prone parts.

```php
class Database {
    // Centralized database handling
}

class UserManager {
    private Database $db;
    /* ... */
}
```

Centralization makes the system more resilient to changes, as modifications are more localized.

#### 21\. **Data Class**

A 'Data Class' is a class that only contains fields and methods for accessing them (like getters and setters) without any additional functionality.

**Problem**: These classes do not encapsulate any behavior, which leads to code that is procedural rather than object-oriented, and it can lead to logic being scattered across the codebase.

**Example**:

```php
class User {
    public $name;
    public $email;

    function getName() {
        return $this->name;
    }

    function getEmail() {
        return $this->email;
    }
}
```

`User` here is a simple container of data without any behavior.

**Solution**: Add behavior to the class that is relevant to the data it holds.

```php
class User {
    private $name;
    private $email;

    function getName() {
        return $this->name;
    }

    function getEmail() {
        return $this->email;
    }

    function sendNotification($message) {
        // Send a notification to the user
    }
}
```

Adding methods that act on the data makes the class more encapsulated and object-oriented.

#### 22\. **Comments**

Reliance on comments to explain complex or unclear code is a code smell. Good code should mostly be self-explanatory.

**Problem**: Excessive use of comments often masks bad code that should be refactored for clarity. Comments can become outdated or misleading if not maintained alongside the code.

**Example**:

```php
// Check if the user is eligible for a discount and apply it
function applyDiscount($user, $order) {
    // ...
}
```

The function's purpose and implementation should be clear without needing comments.

**Solution**: Refactor the code to be more self-explanatory.

```php
function applyDiscountIfEligible($user, $order) {
    if ($this->isUserEligibleForDiscount($user)) {
        $this->applyDiscount($order);
    }
}
```

Refactoring the code into well-named methods reduces the need for comments and makes the code's intent clear.

#### 23\. **Duplicate Code**

'Duplicate Code' is one of the most common code smells where the same code structure is repeated in more than one place.

**Problem**: It makes the codebase larger and more complex than necessary, and if a bug is found in one place, it likely needs to be fixed in multiple places.

**Example**:

```php
function calculateTotalOrder($order) {
    // ...
}

function calculateTotalInvoice($invoice) {
    // Similar code to calculateTotalOrder
}
```

The calculation logic is duplicated in two different functions.

**Solution**: Abstract the duplicated code into a single method or class.

```php
function calculateTotal($items) {
    // Unified calculation logic
}

// Now use calculateTotal in both order and invoice calculations
```

Centralizing the common code reduces duplication and the potential for bugs.

### **Wrapping Up**

Addressing code smells is a continuous and essential process in software development. It's not just about fixing immediate problems but about improving the overall health and maintainability of the codebase. By regularly refactoring to address these issues, developers can ensure their code is clean, efficient, and adaptable for future changes. This practice not only enhances the quality of the current project but also sets a high standard for any future work on the codebase. Remember, clean code leads to a more robust, scalable, and enjoyable development experience.