published on

Sniffing the Architecture - Singleton

In this series, we are looking at various code architecture patterns. In this one, we are going to take a peek at one of the favorite interview warm-up questions there is: what is a singleton?

The definition

Imagine a board game that is played by cards. There are ones that look the same and you need to collect multiple of them in order to get points. In addition to this, there’s a card that makes everyone pass on their cards to the player to the right. There’s only one of this card, and after usage, it gets shuffled back to the deck where everyone draws from.

The cards that you collect to earn points are instances of the same class. They accomplish the same thing. The card-passer is also an instance of a class, however, there’s only one of this card in the deck, since the game’s rules prohibit you from having multiple copies. This card is used by different people (processes) at different times, it can also be dormant in the deck (memory) when not in use. In this case, this card is a singleton.

Probably the example is not perfect (also this made up game is a bit dumb), but you get the gist of it. Now for a proper definition according to Wikipedia:

In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to one.

Dope. Now let’s take a look at what a Typescript implementation of a singleton looks like:

class PassAroundCard {
    public numberOfUses: number;

    private static instance: PassAroundCard;

    private constructor() {
        this.numberOfUses = 0;
    }

    public static getInstance() {
        if (!PassAroundCard.instance) {
            PassAroundCard.instance = new PassAroundCard();
        }
        return PassAroundCard.instance;
    }

    use() {
        this.numberOfUses++;
    }
}

const card = PassAroundCard.getInstance();
const anotherCard = PassAroundCard.getInstance();
console.log(card === anotherCard); // true

card.use()
anotherCard.use()
console.log(card.numberOfUses); // 2

When would you need a singleton?

Singletons are super useful when you’re working in a memory-limited environment. If you create too many instances of a memory-heavy object, you might be taking up the precious bytes that you’d like to use for other things. In this case, a singleton might come in handy to protect yourself from bad code.

Okay, what’s the catch?

Singletons seem like a simple concept but there can be multiple issues with the implementation. For instance, if you’re running a multi-threaded application where you’d like to mutate the singleton itself, you will need to make sure to implement thread-safe locking mechanisms on it. In general, these global mutatable objects are dangerous, unless you super-know what you’re doing.

That’s it for today. Until next time.