Python – how to refactor many singletons

Architecturedesigndesign-patternspython

I have a medium-sized python program (~5000 lines of code), which I've built up over time, with no particular plan as I went ahead. The architecture I've ended up with consists of 5-6 large Singleton objects, each of which handle a certain aspect of my program, such as database comms, a web-server, data gathering client, and internal calculations.

I feel that using several singletons like this doesn't really make use of the true benefit of OO-programming, namely that it easily allows you to create numerous related objects. My singletons are also fairly dependent on each other, and if I grew the program a lot (say ~50 000 lines), I can see my approach becoming spaghetti code.

So I'm wondering if there is a better way of structuring my program. E.g. should my singletons actually be separate modules? But then how would I approach the attributes that are very neatly organised in my singleton objects? Are there other architecture options?

I'm not very familiar with design patterns (the GOF book is on my todo-list) so perhaps there are design and/or architectural patterns that would be better for my program?

Best Answer

Singletons are considered 'evil' by many, and while a singleton pattern has its uses they are few and far between... I've worked with several large codebases and have pretty much always managed to move them away from singletons.

The easiest way to eliminate singletons is:

  1. Introduce an interface on top of your singleton: this allows you to separate the contract from the implementation and reduces the coupling you have to the actual implementation
  2. Provide a setter on your singleton so you can set the singleton instance from a unittest: this allows you to 'swap out' the singleton instance in a unittest.
  3. Create unittests on the class you want to change: using a mock of the interface introduced in 1 and the setter introduced in 2 you can now write unittests on the class.
  4. Inject the singleton instead of getting it statically: in the class that depends on your singleton, have a way to inject that singleton (via the interface created in 1). You can use constructor injection, method-based setters.... Whatever works for you. This is the first time you actually touch the class you are refactoring! The tests introduced in 3 will help you refactor without breaking anything

You can avoid step 2 if you want to do it 'all in', but this approach is the most pure in the sense that you avoid changing any classes that do not have tests to check that nothing breaks. Personally, I find this to be a bit overkill but YMMV. The basic premise is that you move towards a class that has dependencies injected instead of fetched statically.

Also, even IF you have legitimate uses for a singleton you should STILL inject them. Singletons are about ensuring that only a single instance of a given class exists. The classic pattern with a globally-accessible static function achieves this, but unfortunately also moves us away from injecting that instance due to bad example code floating about the web. There are plenty of frameworks out there that can handle dependency injection for you and most of them will have a way to configure an object so that the same instance is reused throughout the application, effectively making this a singleton.

Related Topic