6 ms·
I’m Adam, and i’m a recovering Singleton addict.
- demallien 15y agoWell, two points come to mind: 1) Singletons do make sense when they represent a true physical singleton - for example, you only want one piece of code drawing directly to the screen, the Window Manager, which should indeed be a singleton. 2) Most of your problems stem from the us of GetInstance() not from the use of the Singleton pattern in and of itself. For example, without GetInstance(), the other way to get a reference to the Singleton object is to pass it in to the object that is going to use it. This indicates the dependency in the client class's interface, and also makes mocking out the Singleton for test purposes a real possibility.
- jasonlotito 15y agoQuestion regarding the injection. I've found that while injecting dependencies is good, I still prefer the brevity of not having to declare the common case. Basically, I allow an injection to take place, but make it optional, and if one isn't passed, I use the common case, which in effect makes a call to a getInstance. Any thoughts on that?
- demallien 15y agoWell, that is a workable solution, but then, I'm sure you're already aware of that, seeing as you use it already ;) Personally I prefer having the object appear in the published interface, it helps highlight the existence of a dependency, but your way doesn't seem horrible either. I suspect that it depends a lot the language you're using. I'm a C programmer, and optional parameters are quite verbose in C, so I would never choose your solution, but in Ruby or Javascript your solution could be quite clean.
- jasonlotito 15y agoMy big concern is always implementing a solution and not seeing an otherwise obvious problem. Hence the question. =) As a PHP guy, setting up optional params are easy, so I like the solution.
- aschepis 15y agoI have done that as well. That is one of the strategies we have used on my team @ work. One specific case was where we were basically being integrated into a much larger, older component and they had their own way of doing things. Dependency injection wasn't an option. So we did a default for that case and exposed the dependencies so that we could mock them out in our tests.
- dalke 15y ago"true physical singleton"s have a way of becoming not true. Here's a couple of people who have run multiple window managers at the same time: http://ubuntuforums.org/showthread.php?t=212731 http://ubuntuforums.org/showthread.php?t=212731 http://duopetalflower.blogspot.com/2010/01/running-multiple-window-managers.html http://duopetalflower.blogspot.com/2010/01/running-multiple-... .
- evilbit 15y agoYou are, of course, correct, but I am yet to come across a single production system that uses singleton in that manner that isn't driven by Spring or some other IoC container. Fact of the matter is: canonical implementation of singleton is with getInstance(), so when people rail against Singleton, the getInstance() implementation is implied.
- andos 15y agofor example, you only want one piece of code drawing directly to the screen therein lies the problem: most of us are, in general, terrible at predicting the future. By the time I notice I now want more than one piece of code drawing directly to the screen, my code is already full of wrong assumptions. One way of easing this is -- as you point out -- to make dependencies explicit and abandon GetInstance. Better yet if realizing that, as a design guideline, "needing only one of something" trumps "something being a singleton" any day. This is the kind of future-proofing that generally doesn't hurt the schedule.
- troels 15y ago""Singletons do make sense when they represent a true physical singleton - for example, you only want one piece of code drawing directly to the screen, the Window Manager, which should indeed be a singleton."" That's a false dichotomy. Trying to understand the world as global or local data doesn't make sense; It's contextual. What may be global to you may be local to the next guy and vice versa. What does make sense, is for a programmer to make a judgement call as to whether something could meaningfully be considered global for the particular case he's working on. I used to like the concept of dependency injection, but I have come to find it mostly just adds noise. If you use a dynamic language anyway. I don't know about statically, compiled languages, since I don't do much work in those.
- demallien 15y ago"That's a false dichotomy. Trying to understand the world as global or local data doesn't make sense; It's contextual. What may be global to you may be local to the next guy and vice versa." Err, firstly I didn't present a dichotomy,false or otherwise. http://en.wikipedia.org/wiki/Dichotomy http://en.wikipedia.org/wiki/Dichotomy Secondly, I have no idea what you're talking about. I'm not talking about whether data is global or local, I'm saying that when you have a single physical asset, it doesn't make sense (and sometimes is even flat out wrong) to have more than one object talking to it. You will get into a big mess if you have two NetworkManagers trying to set up the one ethernet port at the same time, as a simple example. Whether that representation is local or global is orthogonal to the problem.
- troels 15y agoUsing the labels "global" and "local" as distinct categories is the dichotomy I referred to. I see them relative values, not absolutes. You can't have something be "global" or "local" - Only "More global" or "More local". I understood that you operate with categories here - Maybe I'm mistaken? Certainly, for a given program it may (or may not) make sense to have a restriction which prevents one type of resource to be assigned more than once. My point being that there is no need to treat this restriction as "special" somehow.
- mattgreenrocks 15y agoMy personal approach is singletons make sense only when: 1. There should be one instance of the data and 2. The data needs to be lazily initialized. Otherwise, you might as well drop the facade and use globals.
- latch 15y agoThe OP is down, but from reading the 1 comment, I'm sure this is a C# (possibly Java) developer. 1- Take a programmer who's tied to an IoC container and DI as a way of life, along with anti-singleton, and interface everything. 2- Introduce him or her to a dynamic language. Specifically focusing on testability without DI, interfaces and fear of singletons and statics. 3- Watch as he or she either: a - accepts the fundamental truth that all that crap in a static language doesn't add value outside of freeing you from the language b - refuses to believe that what you are doing can even be classified as programming This is equally entertaining to do to either a very "experienced" (doing the same thing for the last 10 years) programmer, or someone who's just discovered mocking and mocks everything. You can tell a lot about a Java or C# programmer by how readily he or she accepts this shift (which isn't to say they magically switch over to a dynamic language, but they should recognize that all that stuff a static language demands of us is really a limitation of said languages).
- klodolph 15y agoHm, I think your statements is too broad: "...the stuff a static language demands of us is really a limitation of said languages." You could apply it to some languages, like Java or C#, but the Haskell and ML folks have an entirely different view of static typing. As Haskell has proven, a good static typing system can make it easier to write short, clear code, correct code. And dynamic types are really just a kind of static types -- reduce a static type system until it has only one type, voila, a dynamic type system. I jest. I tend to think about it the other way around, as "These are things I can do in a static type system but not in a dynamic one," but never let it be said that arguing about type systems on the internet was a good use of my time.
- deleted 15y ago[deleted]
- deleted 15y ago[deleted]
- latch 15y agoI guess in pointing out other people's ignorance, I ended up pointing at my own. Thanks though, I guess I should at least familiarizing myself with Haskell before I paint such broad strokes.
- palish 15y agoAs a video game programmer, I use the Singleton pattern quite often. For example, "TextureMgr", "MaterialMgr", "ModelMgr", "GrSubsys" (for Graphics Subsystem), etc.. The most beautiful Singleton code I've seen in C++ is: class GrSubsys { public: GrSubsys(); ~GrSubsys(); }; extern GrSubsys* gGrSubsys; ... then the constructor and destructor are written such that you can startup/shutdown the singleton as follows: //------------------------------------------------------- void App_Startup() { // initialize graphics subsystem. new GrSubsys; } //------------------------------------------------------- void App_Shutdown() { // shutdown the graphics subsystem. delete gGrSubsys; } //------------------------------------------------------- int main() { // startup the engine. AppStartup(); // enter the per-frame application loop. while ( AppFrame() ) { } // shutdown the engine. AppShutdown(); return 0; } Shrug. A friend introduced it to me, and I liked it a lot. The same concept can be easily applied to C, too.
- latch 15y agohow much unit testing do you do?
- palish 15y agoA better question might be, "Would this pattern impact our ability to write unit tests?" I believe the answer is "No." Let's say the module Foo depends on the Graphics subsystem. That is, Foo.cpp has the code: #include "GrSubsys.h" //------------------------------------------------------- Foo::Foo( const string& name ) { // fetch a handle to our model (loading it if necessary). _model = gGrSubsys->GetModel( "models/" + name ); } //------------------------------------------------------- bool Foo::IsValid() { return ( _model != NULL ); } In order to write a unit test that takes into account the aforementioned Singleton pattern, you might write: //------------------------------------------------------- void Test_EngineComponents() { // prepare for science. AppStartup(); //========================== // Test #1 - Foo //========================== { // load a Foo entity. Foo* sunTzu = new Foo( "test/warlord" ); // verify the entity loaded successfully. assert( sunTzu->IsValid() ); // shutdown. delete sunTzu; } // conclude our science. AppShutdown(); } and AppStartup() is the function which initializes the subsystem singletons (and those will initialize their manager singletons). It's about discipline. Any fool can butcher with any tool.
- zoul 15y agoThe post is down, so I can’t comment on that, but getting rid of singletons was the single most effective thing I did to improve my software design. I also summed up my objections to the singleton pattern in a blog post: http://zmotula.tumblr.com/post/1390385240 http://zmotula.tumblr.com/post/1390385240 There’s also a blog post called Singletons Are Pathological Liars by Miško Hevery, which is very well thought-out and contains links to other related topic: http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/ http://misko.hevery.com/2008/08/17/singletons-are-pathologic... Hope that helps somebody, reading Hevery’s articles was a huge eye-opener for me.
- chris_j 15y agoI don't normally do this but Google Cache is being a pain for me so it might be being a pain for others. Here is the original article from http://webcache.googleusercontent.com/search?q=cache:http://adamschepis.com/blog/2011/05/02/im-adam-and-im-a-recovering-singleton-addict/&hl=en&strip=1 http://webcache.googleusercontent.com/search?q=cache:http://... I’m Adam, and i’m a recovering Singleton addict. Posted by aschepis on May 2, 2011 My name is Adam, and i’m a recovering Singleton addict. There, i’ve said it. I used to use singletons all the time because they make doing some things, like sharing state globally, incredibly convenient. My code was littered with XYZManager classes. The defining trait of these classes was the static GetInstance() method that magically enabled me to get access to that object and its state wherever I wanted!! What a great idea, right? What a mess! I learned over time that the cost of changing one of these things, or the cost of doing a major refactor was really high in terms of code change. And to make things worse, because my classes’ dependencies were hidden in implementation and weren’t transparent in the interfaces it was impossible to write real unit tests. This made doing a big refactor even less attractive. So over the years, through work in the industry and coding on my own I’ve come to the conclusion that the singleton sucks, and that there are very few places where they are actually appropriate (logging comes to mind as one acceptable place). The fact of the matter is that most of the places I see singletons used in software they are actually just an enable for developer laziness. So here is my off the cuff list of why singletons suck. Feel free to comment and add your own reasons (or counterpoints) Singletons hide your dependencies. This makes code harder to understand Singletons make unit testing difficult. It’s hard to mock out a global object that you can’t inject into a class Singletons reduce reusability. If i’m writing a class that utilizes a singleton because my application will only ever use one then i’m limiting myself because I can’t use that library to write test tools that may want to simulate how many of these object (for instance, many users) interact with a system. Singletons reduce scalability. A single, global object? Sounds like a source of contention to me. Singletons are not good object oriented design, they are lazy!
- MichaelGG 15y ago>"Singletons are not good object oriented design, they are lazy!" Hmm, so perhaps that says something more about OO than "singleton style"?
- aschepis 15y agoApologies!!!! You guys killed my little ec2 instance! It's back up, but running slowly. I'm going to look for some new hosting. thanks for the comments. i'll take some time to respond later.
- neilk 15y agoSteve Yegge wrote on this some years ago, calling it the Simpleton Pattern. http://sites.google.com/site/steveyegge2/singleton-considered-stupid http://sites.google.com/site/steveyegge2/singleton-considere...
- malkia 15y agoSingleton's are fine, as long as you don't know they are such. For example calling a function, that does lazy initialization (first time init) - is really good - e.g. not requiring certain initialization is sometimes really practical, and does not introduce messiness in your code. Most importantly does not require putting that initialization code throughout every application that you might use. For example, we use at work DEJA Insight Profiler, and you can directly put profile probes (C++) with DEJA_CONTEXT("SomeFunction") - it's using RAII to mark start/end of the probe. But the point is there is no explicit call to DEJA_INIT, or DEJA_CLOSE, etc. But this only works if the DEJA main application is loaded.
- cageface 15y agoIs it just me or have there been a lot of content-free short opinion pieces on software here lately? I expect a lot more nuanced and detailed critique than "x is bad".