Skip to content

Latest commit

 

History

History
153 lines (94 loc) · 3.87 KB

File metadata and controls

153 lines (94 loc) · 3.87 KB

Code Smell 32 - Singletons

Code Smell 32 - Singletons

The most used and (in)famous design pattern in the world is causing us great harm.

TL;DR: Don't use Singletons. Ever.

Problems

  • Coupling

  • Testability

  • Accidental problems

  • Multi threading

  • Premature Optimization

Code Smell 20 - Premature Optimization

Solutions

  1. Avoid it.

  2. Use contextual unique objects.

  3. Benchmark object creation.

Examples

  • Database Access

  • Globals

  • Logging

Sample Code

Wrong

<?

class God {
    private static $instance = null;

    private function __construct() { }

    public static function getInstance() {
    if (null === self::$instance) {
        self::$instance = new self();
    }
    return self::$instance;
   }
}

Right

<?

interface Religion {
    // Define common behavior for religions
}

final class God {
    // Different religions have different beliefs
}

final class PolythiesticReligion implements Religion {
    private $gods;

    public function __construct(Collection $gods) {
        $this->gods = $gods;
    }
}

final class MonotheisticReligion implements Religion {
    private $godInstance;

    public function __construct(God $onlyGod) {
        $this->godInstance = $onlyGod;
    }
}

// According to Christianity and some other religions,
// there’s only one God.
// This does not hold for other religions.

$christianGod = new God();
$christianReligion = new MonotheisticReligion($christianGod);
// Under this context God is unique.
// You cannot create or change a new one.
// This is a scoped global.

$jupiter = new God();
$saturn = new God();
$mythogicalReligion = new PolythiesticReligion([$jupiter, $saturn]);

// Gods are unique (or not) according to context
// You can create test religions with or without unicity
// This is less coupled since you break the direct reference to God class
// God class Single Responsibility is to create gods. Not to manage them

Detection

This is a design pattern. We should avoid it by policy.

We can add linter rules for patterns like 'getInstance()' so new developers cannot infect code with this anti-pattern.

Tags

  • Globals

Conclusion

This is an historical mistake already acknowledged by the community. Nevertheless, lazy developers bring it up again and again. We need to reach a consensus on its drawbacks.

Relations

Code Smell 06 - Too Clever Programmer

Code Smell 25 - Pattern Abusers

More Info

Singleton - The root of all evil

Credits

Photo by Maria Teneva on Unsplash


The Diagram is Not the Model. The model is not the diagram. It is an abstraction, a set of concepts and relationships between them.

Eric Evans

Software Engineering Great Quotes


This article is part of the CodeSmell Series.

How to Find the Stinky Parts of your Code