Posts in legacy code

The Recipe for Singletons Removal

Singleton Banner

We all went through it, am I right? You join a new company, you jump on the new codebase, you find lots of singletons, get used to them, become friend with them, but after some time you realize it’s time to terminate the friendship.

For a greater good.

And for better testing, of course. And for proper dependency injection, of course. And for your own sanity, of course.

After years in this field you should well know that singletons are bad, if you don’t… well… argh, I have bad news for you 🙃, but also a few articles, yes.

So here is a simple recipe to follow in order to have your app/code free from singletons. To some of you, this could all seem very obvious, and you might also know that I don’t write about obvious stuff, but tonight I’m tipsy and I had confirmation that most people are still unsure on how to get around such situations.

The recipe

1) Make a list of the singletons in the app and the dependencies between them.

2) Starting from the most high-level singleton (the one using the others more), apply the following for each one of them:

⦿ create a property in every class that reference the singleton at least once

⦿ substitute all the references to the singleton with the reference to the property

⦿ create a lazy getter returning the singleton or assign the singleton to the property where more appropriate (in the viewDidLoad for ViewControllers or generally speaking the init methods)

⦿ about the usages of singletons in static methods: refactor the code and turn those methods into instance methods as it surely is crap (this will allow dependency injection)

⦿ about the usages of singletons in categories:

→ if you own the class, publicly expose the property in the class

→ if we class comes from a framework (e.g. UIViewController) refactor the code by removing the category (it was probably bad code since the beginning)

⦿ build the app and make sure it still behaves as expected

⦿ make sure the (unit|automation) tests are still green

⦿ for every class using the singleton, modify it so that:

→ if the class is a ViewController, we prefer going for dependency setting rather that dependency injection as the view controller might be accessed via a segue (segue.destinationViewController). In this case, assert that the dependency is set in the viewDidLoad

→ otherwise, modify the designated initializer having it accepting a dependency via injection as per standard dependency injection. Keep the init chain correct (Obj-C & Swift)

⦿ modify the caller chain back up until the root object (most likely the AppDelegate) instantiates an instance of the original singleton and pass it down the chain

⦿ build the app and make sure it still behaves as expected

⦿ make sure the unit tests are still green

Show me the way

Really? Do I have to? Ok, let’s do something quick. Code is in Objective-C because singletons can be more easily found in legacy codebases… it is well-known that nobody writes singletons in Swift these days! Shots fired. 🎭

written in ios, legacy code, singleton Read on →