DEV Community

Cover image for Code Smell 32 - Singletons
Maxi Contieri
Maxi Contieri

Posted on • Edited on • Originally published at maximilianocontieri.com

1 1

Code Smell 32 - Singletons

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

Problems

  • Coupling

  • Testability

  • Accidental implementation problems.

  • Multi threading issues.

  • Static methods polluting.

  • Object creation contract violation.

  • Bijection mismatch.

  • Memory issues.

  • Premature Optimization.

Solutions

  1. Avoid it.

  2. Use contextual unique objects.

  3. Benchmark object creation.

Examples

  • Database Access

  • Globals

  • Loggers

  • Helpers

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;
}
}
view raw Singleton.php hosted with ❤ by GitHub

God is the archetypical singleton example.

<?
final class God extends Singleton {
}
$christianGod = new God();
<?
$christianGod = God::getInstance();
// Why should us be aware of getInstance when creating an object ?

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 again and again. We need to reach a consensus on its drawbacks.

Relations

More info

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

Image of Timescale

Timescale – the developer's data platform for modern apps, built on PostgreSQL

Timescale Cloud is PostgreSQL optimized for speed, scale, and performance. Over 3 million IoT, AI, crypto, and dev tool apps are powered by Timescale. Try it free today! No credit card required.

Try free

Top comments (2)

Collapse
 
yoursunny profile image
Junxiao Shi

How is GodFactory supposed to be used if it always throws?

Collapse
 
mcsee profile image
Maxi Contieri

Hi. I changed the example and removed factory usage since I think it was a bit confusing

The best way to debug slow web pages cover image

The best way to debug slow web pages

Tools like Page Speed Insights and Google Lighthouse are great for providing advice for front end performance issues. But what these tools can’t do, is evaluate performance across your entire stack of distributed services and applications.

Watch video