ApiaryActive
Try: pause · settings · learn · wipe
← Community / Reading Room
SP
patterns · 2 min read

singleton pattern when not

===========================================================

===========================================================

The singleton pattern is a creational design pattern that restricts a class from instantiating multiple objects, ensuring a single instance throughout the application's lifetime. While it may seem useful for configuration or caching, we'll explore when it makes sense and when it can hurt your APIary platform.

When It Makes Sense: Configuration

In some cases, using a singleton for configuration is acceptable. This pattern ensures that only one instance of the configuration object exists throughout the application's lifetime.

// config.js (singleton)
class Config {
  private static _instance;
  public static get instance() {
    if (!Config._instance) {
      Config._instance = new Config();
    }
    return Config._instance;
  }

  constructor() {
    this.databaseUrl = 'mongodb://localhost:27017';
    this.apiKey = 'my-secret-api-key';
  }
}

// Usage
const config = Config.instance;
console.log(config.databaseUrl); // Output: mongodb://localhost:27017

In the above example, we use a singleton to ensure that only one instance of the Config class exists. This helps maintain consistency across the application.

When It Hurts: Testing

One significant drawback of the singleton pattern is its impact on testing. Since instances are shared throughout the application, mocking or stubbing becomes challenging.

// test.js (example of a failing test due to singleton)
const sinon = require('sinon');
const Config = require('./config');

describe('MyService', () => {
  it('should use the correct database URL', () => {
    const configStub = sinon.stub(Config, 'instance').returns({
      databaseUrl: 'mongodb://test-server:27017',
    });
    // ...
  });
});

In this example, we attempt to stub the Config instance using Sinon. However, since the singleton pattern ensures a single instance exists, our test will fail because it's trying to create a new instance.

Avoid in Modern JavaScript

Modern JavaScript frameworks and libraries often discourage the use of singletons due to their limitations and potential drawbacks. Consider alternative approaches, such as:

  • Dependency injection
  • Factory functions
  • Class-based constructors with lazy loading

Why Singleton Hurts Performance

Singletons can lead to performance issues when dealing with large-scale applications or concurrent requests. Here's an example:

// service.js (example of a singleton causing performance issues)
class Service {
  private static _instance;
  public static get instance() {
    if (!Service._instance) {
      Service._instance = new Service();
    }
    return Service._instance;
  }

  constructor() {
    // Simulate some expensive initialization process
    setTimeout(() => {}, 1000);
  }

  doSomething() {}
}

// Usage (multiple instances causing performance issues)
const instance1 = Service.instance;
const instance2 = Service.instance;

// Both instances share the same initialization process, leading to unnecessary overhead

In this example, we create multiple instances of the Service class using a singleton. However, since both instances share the same initialization process, it's executed twice, causing performance issues.

Conclusion

While the singleton pattern may seem useful for configuration or caching, its limitations and potential drawbacks make it less desirable in modern JavaScript development. When possible, consider alternative approaches to avoid singletons and their associated problems.

Related/Sources

Frequently asked
What is singleton pattern when not about?
===========================================================
What should you know about when It Makes Sense: Configuration?
In some cases, using a singleton for configuration is acceptable. This pattern ensures that only one instance of the configuration object exists throughout the application's lifetime.
What should you know about when It Hurts: Testing?
One significant drawback of the singleton pattern is its impact on testing. Since instances are shared throughout the application, mocking or stubbing becomes challenging.
What should you know about avoid in Modern JavaScript?
Modern JavaScript frameworks and libraries often discourage the use of singletons due to their limitations and potential drawbacks. Consider alternative approaches, such as:
What should you know about why Singleton Hurts Performance?
Singletons can lead to performance issues when dealing with large-scale applications or concurrent requests. Here's an example:
References & sources
  1. Apiary Reading RoomOpen, cited knowledge base — funded to keep bee & practical research free.
From the Apiary Reading Room. Opinion & editorial — not financial advice. We don't overclaim.
More from the Reading Room