Rant on Singleton

One pattern that has been a topic of hot debate the use of “Singletons.” What was once a widely accepted design pattern has long begun to be viewed under a skeptical eye, potentially rendering it a less desirable coding practice among developers. The primary criticism of singletons pertains to their introduction of global state into your program, giving way to unrestricted access, irrespective of the scope. Another aspect is the magic knowledge a developer would need of all the nifty litte singleons there are in your codebase. I cannot see how ayone would prefer this over sending an actual argument to a method.

The Drawbacks of Global State

Firstly, global state makes programs hard to test. An important feature that facilitates testability is the loose coupling of classes. This allows you to isolate an individual class for intensive testing. If a class is using a singleton (with reference to a conventional singleton that upholds its uniqueness via a static getInstance() method), it becomes inseparable from the singleton. This coupling makes it impossible to test the user independently from the singleton.

In many scenarios, this becomes a prohibitive factor for developers attempting to test a class, especially if the singleton corresponds to a resource that must not be affected by tests (like a critical database). An optimal solution would entail supplying the singleton as a parameter during the user’s constructor to allow testers to effortlessly create a singleton mock for tests. By shifting the enforcement of the singularity to the client or a factory class instead of the singleton itself, we can eliminate global state completely. It’s worth noting that it’s generally considered a breach of the Single Responsibility Principle of OO design if an entity is tasked with maintaining its own singularity as well as executing its key tasks.

Secondly, programs using global state keep their dependencies concealed. Singletons gain the ability to be accessed anywhere through their generic static method (i.e. getInstance()), allowing it to be used within a method devoid of specific parameter transmission. While this may seem like a programmer’s delight, depending on this static instance equates to method signatures losing their revelatory nature about dependencies. Instead, the method is enabled to access the singleton improbably. This necessitates users to have insight into the inner mechanisms of the code to use it effectively, making it more challenging to use and test.

Mental overload

Relying on singletons will make your code totally impossible to work with from a productivity point of view. All developers would need to know about all the singletons you have created (and belive me those things spread like wildfire once you set them loose). So instead of having nice parameters for your methods, you need to look through a catalog (in documentation?) of singletons and figure out what they do and use them. Compare:

public void addNewMember() {
  // I need to know about two singletons to do my job
  String name = MemberView.getInstance().getMemberName();
  String email = MemberView.getInstance().getMemberEmail();

  MemberRepo.getInstance().addMember(name, email)
}
public void addNewMember(MemberRepo r, MemberView v) {
  // I have what I need in the arguments
  String name = v.getMemberName();
  String email = v.getMemberEmail();

  r.addMember(name, email)
}

In addition, the singleton’s use of static variables prohibits the use of polymorphic operations, we can not overload the getInstance method and thus we make the whole application less soft and harder to change, especially during runtime. I.e. having multiple views in the MVC pattern.

Singleton’s Impact on Testing

Moreover, the paired challenges of singletons come into the spotlight in today’s age of test-driven and agile development, where it is crucial to have concise tests covering large portions of your codebase. One important quality of these tests is that they should have the potential to be executed in any sequence, without dependence on each other. However, singleton usage might pose a challenge to this because dependencies of certain methods become obscure when they rely on singletons (accessed from static getters). Therefore, a tester may inadvertently write two tests dependent on each other due to the modification of a shared resource (the singleton). This could result in unreliable tests that succeed or fail based on their execution order.

Actual use of Singleton

Well… basically never, not in the form of the globally accessible variable repository. The focus of the pattern was actually to prohibit multiple instances of some class and this could be a neat thing in some rare cases (honestly very few). This could also be solved by some other means. E.g. throwing exceptions from the constructor if you create more instances of a class, that would force you to send arguments like a good developer.

tags: programming, - desing

💬 Comments

Post comment
Loading...