4

I'm new to Programmers and I am looking to increase my knowledge of programming. Recently, a user on Stack Overflow told me using singletons is a bad idea, that they encourage tight coupling and that they make testing harder.

What prompted this discussion was that every class I've ever written accessed any kind of data through a singleton. For example, a class that handles state data for a game. If any other class wanted to access this data, all they would have to do is get the singletons instance and there it would be. Specifically, instantiating a class on the AppDelegate, then accessing it via: [[[[UIApplication sharedApplication] delegate] gameObject] getScore].

The SO user told me that I should instantiate the 'gameObject' wherever I first need it, then pass that object to every other class that needs it via either a method as an argument, or via a property.

I was discussing these points when someone else pointed out that this information is completely wrong, that singletons are unrelated to coupling and that they do not affect testing at all.

I'm now completely confused as to which person is correct. Could someone please clarify which technique is best for an object to persist for the lifetime of the app, and be accessible to other classes, and also maintain loose coupling. To me, the object passing by method or property to each class seems the most logical, but I do not know!

Thanks in advance for any help!

0

7 Answers 7

6

You won't ever know. Program design is about tradeoffs, and analyzing particular scenarios to produce a solution that is good (not best) given what you know about them. In this particular scenario, the singleton proponent is decidedly incorrect but you're missing the point.

In scenarios where the answer is less clear cut, you're going to need to be able to think things through yourself to judge what is a good or bad approach for the problem at hand. If you know what coupling is, and what a singleton is then you shouldn't really need to ask us. It's important to develop this skill for those many times when the particulars of the scenario mean we can't get you an answer.

5
  • 2
    I have tried reading a lot of sources on the topics of coupling, encapsulation, etc but I do not think I fully understand them. Do you have any recommended reading concerning design patterns that will help me understand? Also, I think from what I understand, passing an object forward down the stack via a method is Dependency Injection, is this correct? Excuse me if I am not using the correct terminology, I am moving from a programmer who just 'got things to work' to a programmer that wants to think deeper about design patterns and correct ways of solving problems. Commented May 17, 2012 at 19:45
  • @bitbucket: Ugh. Think about design; not patterns. Reading about patterns won't teach you (at least teach you well) about the largely unrelated concept of coupling. There is no incorrect way of solving problems if your problem gets solved; just shades of grey. Patterns exist because programmers needed a name for common approaches which yielded usually better designs, not because they're somehow 'correct'.
    – Telastyn
    Commented May 17, 2012 at 20:15
  • Well, I am trying to research these 'common approaches' in order to become a better programmer. Do you have recommended reading about software design? Commented May 17, 2012 at 20:37
  • @Bitbucket: there's not a lot of reading I would suggest. Getting a feel for what coupling and encapsulation mean can be done with a generic Internet search, but getting better at program design involves practice.
    – Telastyn
    Commented May 17, 2012 at 20:50
  • Okay I will do some research online. Thank you for your help! Commented May 17, 2012 at 21:01
12

The part that creates coupling isn't the fact that the variable lives in a singleton, but that your client object goes and fetches it from there itself. This means that you could never change the way your object is stored without introducing all kinds of hassle for yourself (assuming, as you say, that many objects behave this way).

Consider what would happen, for example, if you decided you wanted your program to be MDI (multi-document interface) so the user could play more than one game at once. Since your entire program accesses this singleton, you've pretty much screwed yourself.

On the other hand, you can store the game in the singleton and then inject it into objects that need to access it. Look up Dependency Injection. I don't know why you'd have a singleton at that point but maybe it wouldn't be completely pointless.

Basically, they're both right.

1
  • This was really helpful, especially the explanation of coupling and dependency injection. If I could upvote I would! Commented May 18, 2012 at 8:12
4

Regarding the Singleton, consider a case where you want to test a class that uses a Singleton, but you wish to mock it. You can do it by extracting a method called getSingleton and then overriding it in a testable subclass, but it gets messy this way.

Your class will be more testable if it accepts the dependency on the other class in the constructor. You can then inject a mock dependency in your tests.

If you apply this throughout your project, you will discover you don't need any Singletons anymore, but you do need to "wire" your project up basically from the main method.

Guice is a DI framework that helps with this, but I recommend playing with it manually first, so you learn the concepts.

If you want to learn more, I really recommend what Miško Hevery has to say.

Videos:

Blogs:

1
  • I am now watching the videos and I will try to absorb as much as possible. Thank you! Commented May 18, 2012 at 8:14
2

At the end of the day, you have to do what makes the most sense you you. Singletons are fine. If they've worked for you, use them.

The problem with them is that you may need more than one of them someday. Your game program may want to juggle two or more games at the same time. Then you have track down every reference to your GameObject and replace it with something more elaborate. The cost of allowing multiple gameObjects from the start is a lot less than retro-fitting the capability later and only slightly more than sticking with a singleton GameObject for the whole life of the program.

If you are certain you will never have multiple games, it's cheaper to go with the singleton. (Although avoiding them might help improve your programming skills--it might be good practice for times when you can't use singletons.) Personally, I've spent enough time getting rid of singletons in my code that I'll avoid them now at all costs.

In your case, singletons are not related to coupling and do not affect testing at all (other than the complete retesting you have to do after removing them).

However, if your code responded to web HTTP requests, and hence might run in hundreds of threads simultaneously, accessing singletons (and, for that matter, any data visible to more than one thread) becomes very tricky. If you don't understand multi-threading programming real well, you are going to cause a major train wreck. The values in the singleton will change at any time. Bugs will be unrepeatable, because they depend on the precise timing of several threads. Reliable testing becomes impossible.

There are a lot of people doing this kind of programming. They don't understand multi-threading. And the people who have to clean up after them feel very strongly that they should not use singletons. This is what the user on SO is talking about. (I think he was advising you to create a new gameObject for each individual HTTP request.) I doubt this is relevant to you, but it helps to know what everyone is talking about.

1

Singletons are very much like global variables with a namespace. Almost all people tell you global variables are bad, but somehow, Singletons are ok.

Having said that, Singletons have some specific uses. It can be used when you definitely want one instance of something. For example - you want only 10 Database Threads, otherwise your database server will crash under load. Your ThreadPool class then should be a Singleton, and manage the DB threadpool.

Another use may be if you have read-only ( or rarely changing ) configs which are essentially global variables. In this case it would save memory and occasional file IO to have it as a Singleton.

In your example - you want to have a GameState as a Singleton. Why would you limit your program to one game? Even if you wanted one game initially, you are restricting yourself by putting singleton logic in the GameState class.

I'm not sure of your application - but I would have created a Game Object separately :

void startGame() {
    Game gs = new Game();
    gs.play();
}

Now how do we find the score? Depends on who needs the score. If I assume the Game class owns the score, then it can have a getScore() function. Sometimes a Player may need a score. This can be solved by letting the Players have a Game reference.

void startGame(Player[] players) {
    Game gs = new Game();
    for ( Player player : players ) {
        player.registerForGame(this);
    }
    gs.addPlayers(players);
    gs.play();
}
Player::registerForGame(Game game) {
    this.currentGame = game;
}

The code is not in any particular language - just an illustration of how it could be designed without singletons. Also, I don't claim this to be a "good" design - for example the Game class will probably to too much here, if the Game has lots of functionality.

As someone mentioned design is just a lot of tradeoffs and you have to do what makes sense for a particular problem.

5
  • Thank you. I now understand design is about tradeoffs and that Design Patterns (like the singleton pattern) aren't strictly something to adhere to, they are just solutions to common problems. Commented May 18, 2012 at 8:17
  • Yes. But remember, the art of design is to use the right solution/tool/pattern at the right place.
    – Chip
    Commented May 18, 2012 at 8:20
  • 2
    And I guess the only way to perfect the art of software design is to jump in and make mistakes and learn the craft by doing it? I may look on google to see if there are any books/references more on software design than patterns. Commented May 18, 2012 at 8:23
  • Yes!!! the more you design the better you are at it!!
    – Chip
    Commented May 18, 2012 at 8:24
  • 1
    @BitBucket: and make sure you come back to your pet projects a couple of weeks / months later and try to change something fundamental in it: like catering for two games played simultaneously. It is when trying to adapt an existing design to new requirements that you really come to understand the shortcomings and pitfalls of previous design decisions. Commented May 18, 2012 at 8:39
0

Well, let's start with singletons.

I'm a JS/client-side web dev who has just recently decided to implement singletons. I'm writing UI objects that are somewhat monolithic in that they represent all UI elements of a given type on a page. The UI object is factory, warehouse, and event/interface manager.

The point in building and managing all instances of these UI elements of a given type from the same type-representing object is that sometimes in UI I want to deal with one UI element at a time and sometimes I want all of them to respond to the same event. Also, it makes it easier to create a more event-driven interface, which is something I've been geeking out on as of late.

But if I were to allow multiple factories from the same constructor, I'd have a nasty or at least clumsy time of trying to to hit all the UI elements with a global event, for instance, because each general UI type object instance would only have the references to UI elements that it actually built. Instead, my general UI type object factory methods will simply return a reference to the original objects when they've already been created. One Class/Constructor. One Instance.

The short version:

Singletons are about preventing multiple instantiations when having multiple instantiations might cause a problem. The end.

Now moving away from Singletons, the subject of tight-coupling:

Tight coupling is typically about excess dependencies. One big fat global object that's containing way too much state information without any means of verifying where that info came from might be problematic, but it's not tight-coupling. When things are too-tightly-coupled, I touch one function or object or random element of the environment (like say an HTML class on the web) and boom everything breaks.

Passing a reference to the same object around excessively and in weird/random ways could result in a tightly coupled-scenario, but mostly it's a good idea when you know your refs from your vars/properties that are getting passed by value and capitalizing on that knowledge wisely.

6
  • 1
    But as noted above, a class that goes and fetches data itself, without exposing its needs through its interface via its constructor (object ref as parameter) or via an ivar or property is tightly coupled. If I understand correctly that is? Commented May 18, 2012 at 8:20
  • A Class/Object does things and owns its own data. A class/object will not go and fetch data, it will go and fetch the object which owns the data and tell it to do things via the other object's interface.
    – Chip
    Commented May 18, 2012 at 8:46
  • So rather than ClassA doing things with ClassB's data directly, ClassA should call a method on ClassB so that ClassB changes its own data. Is that correct? Commented May 18, 2012 at 9:04
  • When Object A asserts a need and Object B or later Object C can address that need without Object A asserting that need differently, you have loose coupling. Regardless of language or OOP paradigm this typically involves the use of some sort of intermediary to handle requests. Commented May 24, 2012 at 19:41
  • @Chip, OOP isn't about one absolute way to write every class and please note that I'm not suggesting that none of your objects should call each other directly. Just the ones where there would be utility in being able to swap objects out on the fly or one data model might be useful to multiple views or controllers a la MVC. I generally architect for my macro/aggregate objects to be loose while internal object components call each other directly. Commented May 24, 2012 at 19:50
0

Decoupling has value if you plan on reusing your code (maybe making a multi-game server, for instance) or on creating unit tests for continued development or team development.

However, the time and effort to decouple your code might be completely wasted if you never reuse or need to further test your code (e.g. the game works, but doesn't sell well, so you move on to some other project). Furthermore, too much decoupling in the innermost loops of a compute engine (physics simulation, etc.) can actually waste a users battery life (e.g. not be "green").

The added value of decoupling might come into play if your game is a sleeper, starts to sell well next year, and your have to come back and read your code to update the app. Then decoupling to add readability, potential code reuse and testability will end up having value after all.

It's a trade-off and a gamble. Many large mission critical projects have to gamble that decoupling adds value (and almost always win that bet). For many small apps that go to die in an app store, the gamble may be a complete loss.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.