Hacker News new | ask | show | jobs
I’m Adam, and i’m a recovering Singleton addict. (adamschepis.com)
30 points by aschepis 5534 days ago
10 comments

The 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).

Hm, 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.

Would you care to elaborate a bit?

It seems your argument is basically: "HA HA look at the static language developers, aren't they stupid! They need to accept some fundamental truths and find their freedom!".

I'm interested in what you have to say but I'd like to actually hear some technical reasons to support your argument.

How do you test code that relies on the current time in C#/Java. I've seen a couple solution. Injecting some type of abstract Clock/SystemClock everywhere being common. C#'s lambda's let you do something nicer, like:

  class SystemTime
  {
    public Func<DateTime> Now => () = DateTime.Now;
  }
Ultimately though, you're having to work around the fact that Java and C# are class-oriented, rather than object-oriented. Classes are useful - they serve as a template for your object, but in most (all?) dynamic languages, the class itself is a living, breathing, modifiable, runtime object.

What does all this mean? How do you get the current time in a testable manner in Ruby? Use Time.now. You don't implement patterns or change your code. You don't fear the evil static..because really, it isn't a static - we don't even call it a static. It's just another method on another class, which we can rewrite at runtime as need be.

How do you stub it? Well, using a mocking framework:

Time.stub!(:now).and_return(Time.local(2011, 5, 3, 0, 1, 22))

The mechanics of how this is internally done isn't too complicated once you know about Ruby's metaprogramming (which probably takes around the same amount of time as getting familiar with C# or Java's reflection capabilities).

I know, it's a simple example. But it's surprisingly common. And I find it a little ridiculous that to get the time, we need to start creating interfaces and injecting parameters. While C#'s lambda's largely solve this problem, move to something just slightly more complicated, and you're back at square one.

I dunno, not sure if that explained it without being condescending. I'm tired...that stub is actually returning a pretty accurate time for me.

That's a nice explanation, without any of the bits I disliked from the original post, I appreciate it. :)

Essentially the benefit we're pushing here is cheap decoupling where in static languages you're having to set this kind of arduous plumbing up yourself, aye?

Right, with dynamic languages, decoupling is a language feature, not a design decision. It's one of the things that I feel make dynamic languages so much more productive. I work with large Java/C# applications. The loss of productivity due to dealing with traditional dependency handling, both at the implementation and at the test level, is significant.

I'm not going to say that it's as big a leap as automatic garbage collection (because, I don't think it is), but I see similarities between a C++ developer who doesn't understand why Java/C# don't have a malloc and delete method, and a Java/C# developer who doesn't understand why XYZ don't have interfaces nor use DI.

We spend so much time doing something a certain way, that it's hard to see how, given a different context (a new language) what we were trying so hard to avoid in the first place, just works.

Wait, I spend 99% of my time programming in dynamic languages, and I still use dependency injection. Why would I want to resort to hacks when I can just pass stuff in to my classes instead?

I will admit that I need the hacks from time to time, though. Recently, I wrote an overly large method that calls a callback when the command completes. For my test, I needed to run a bit of code right before the callback was called.

Runtime role application to the rescue! In my test, I wrote:

    my $done = AnyEvent->condvar;
    $done->begin;
    my $called_callback = 0;

    { pacakge FixupCallback;
      requires 'update_table';
      around 'update_table' => sub {
          my ($orig, $self, @args) = @_;
          my $cb = pop @args;

          # this is like "super"
          $self->$orig( @args, sub {
              $called_callback = 1;
              $cb->(@_);  # call the original callback
              $done->end; # then return control flow back to us
          });
      };
    }
Then, I just find the instance of the class that I need to tweak:

   my $view = $app->latency_publisher->view;
   FixupCallback->meta->apply($view);
And now I've fixed up the code enough to write a sane test. While cool, this doesn't negate the need for dependency injection. I want my app code to be 99% clean, and use the hacks for that 1% case where the hacks result in cleaner code than "the right way".

Also, I've never programmed Java or C#, so don't say that I have inherited bad habits from those languages :)

Singleton pattern overuse is pretty common among PHP developers, probably due to lack of namespaces (until recently).
Well, 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.

for 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.

""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.

"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

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.

Using 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.

Yes, but I didn't use the labels "global" and "local", so why on earth are you still going on about them as though I had?
Question 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?

Well, 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.
My 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.

I 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.
You 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.

"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://duopetalflower.blogspot.com/2010/01/running-multiple-... .
My 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.

I 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://...

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!

Steve Yegge wrote on this some years ago, calling it the Simpleton Pattern. http://sites.google.com/site/steveyegge2/singleton-considere...
Apologies!!!! 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.
As 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.
We used a lot of singletons (also video game deveoper) in the past, to the point where the code is unreadable:

some_system::get_instance()->MemberFunc(), instead of sys->MemberFunc()

Problem came apparent when somebody had made the Camera singleton, and it was singleton...

Nowadays we have one keyboard, one mouse, one printer... We used to have one DISPLAY, even one WINDOW (fullscreen), and one JOYSTICK. Just to get the point...

how much unit testing do you do?
A 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.

Unless I have missed something about unit testing somewhere I am pretty sure that fails the "unit" part of unit testing. Unless that "#include GrSubsys.h" is actually importing a mock graphics subsystem.
A mock graphics subsystem isn't possible since it depends directly on the video card.
My initial point was that the code isn't really unit testable. From what I know, this is common in video games..too much code tied too hardware.

I'm certainly not saying this is bad. I am saying that, from my experience, video game programming is very different than other sorts of programming.

Sorry fella but you don't understand the concept of unit testing. I suggest you do some reading on the subject.

http://en.wikipedia.org/wiki/Unit_testing

Singleton'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.

The 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

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-pathologic...

Hope that helps somebody, reading Hevery’s articles was a huge eye-opener for me.

Is 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".
>"Singletons are not good object oriented design, they are lazy!"

Hmm, so perhaps that says something more about OO than "singleton style"?