Hacker News new | comments | show | ask | jobs | submit login
The Case for Singletons (eamann.com)
28 points by krogsgard 1665 days ago | hide | past | web | 74 comments | favorite



Necessary singletons are a sign that your language/library either embraces "everything is a class" so you have to make vacuous singleton classes to get full access to the language, or it is lacking a sufficiently powerful module system so you have to implement an ad-hoc one yourself using classes.

Unnecessary singletons are usually a sign that someone, somewhere designed a way too general system that allowed multiple instances of something, then nobody ever used that feature, then someone else came in and made things a bit saner by adding a singleton constraint, leaving vestigial object-ness and meaningless pointers being passed around everywhere.

In a perfect world with perfect programmers you'd never see one so the instinct that they smell bad is correct.


> Unnecessary singletons are usually a sign that someone, somewhere designed a way too general system that allowed multiple instances of something, then nobody ever used that feature, then someone else came in and made things a bit saner by adding a singleton constraint

I fail to see how that makes anything saner.


If your program has an unused and untested capability, killing it is a move in the right direction even if it makes your program less elegant. Bad behavior is worse than ugly design.

Of course the right thing to do is to simplify the rest of the program to take advantage of the new assumption but maintenance programmers don't always have the luxury.


Downvote away -- I know I deserve it, but I need to say this:

Whenever I see a discussion of good software design principles given by a PHP programmer, with PHP examples, I roll my eyes and press Back.

Rightly or wrongly, the thought that goes through my head as a former PHP programmer (from versions 3 - 5.x, ending in ~2010) is something like, "if this person knew anything about well-designed software, they'd know enough to use a well-designed language."


Nope, I'll upvote :-)

I started my career as a .Net developer and still work a great deal with .Net (primarily C#) code. I use PHP for work because that's what WordPress is built on and, without rewriting the platform that powers a huge chunk of the Internet, I have to use it. When in Rome ...

And I never said singletons were a good software design principal - just that they have a place and a purpose (even if rarely).


Regarding specifically WP, which is how I made ends meet (and then more) for a number of years -- it's like crack, you hate it and you know you're better than this, but it's just makes life so easy if you don't resist. Not a perfect analogy, but what I'm trying to say is that, yes it's easy and you're fighting the uphill battle if you don't go with it. Plus, WP consulting can be very profitable, given how much of your code can be reused from project to project.

But, I have to say, at this time the flaws of WP are so well-known, and the direction and style of the WP devs are such a known quantity, that we as users/devs know what it is and we know exactly how good/bad it's going to be. It's never going to be a well-designed MVC application, and it's probably never going to conform to good OOP design either. It will probably continue to look pretty nice on the backend, but remain really annoying to extend for anyone but the greenest noobs. And it will probably have a ton of features which seem like bloat to people who simply want a blog, and like cruft to people who want a full-fledged CMS.

I think, after so many years, the cost of building a reusable system from scratch is starting to outweigh the benefit of just sticking with WP. One of the major pillars supporting WP's proliferation is the ease with which one can find hosting -- just upload your site, if it doesn't have push-button install already -- and I think the ease with which a Python or Ruby app can be deployed has now matched that. At least for a certain range of users.


I completely agree. Why has nobody made a WP replacement in rails yet?


See my reply to you about why above.


I had precisely the same reaction. I'm used to seeing singletons in the context of Java. The reasons to want a singleton pattern seems obvious to me but I would only describe it the way its classically described if I was using a crappy language like Java. In Ruby or Python you just call it class that never needs to be instantiated (and it looks way cleaner). Then I see we're talking about PHP and my reaction is if your doing something complex enough to need a singleton then why aren't you using a real language?


If they goal is to target the WordPress user base then the question of "why aren't you using a real language?" is moot.


For some it's more important the market they are addressing than the language they are using. WordPress is written in PHP and has over 17% of the web at this point. If you want to address the WordPress market as the author of the referenced post does, there is no option to switch languages. "Use the right tool for the job," as so many developers like to say. For WordPress the right tool is PHP.


A statement like this doesn't help anyone.

It doesn't help the productive PHP programmer get a better understanding of other (possibly better) tools that exist, what problems they solve, and how they can transition to those tools.

It also doesn't help the person making the statement convey their expertise in the subject matter. Instead it looks like an easily dismissed statement about PHP, without any real attempt to prove it.


The problems of PHP have been well documented here: http://me.veekun.com/blog/2012/04/09/php-a-fractal-of-bad-de... I think its relevant that PHP does object and classes in terrible backwards ways and, among other things, a singleton will necessarily be rather ugly in this context. Learning about singletons won't help anyone get a better understanding of other tools that exist. Learn Ruby or Python if you want to do web programming.


It's like people in Ferraris yelling at people in Toyotas.


It's more like people in cars yelling at people who have attached wheels and diesel engines to horses.


What?


Except if Ferraris were also really slow in addition to having bad gas mileage.


You mixed up the references. But my point is that the argument is philosophical. And doesn't really matter.

People are out building and shipping stuff in PHP, .NET, Ruby, Python, C and foobar. And it all works. And users don't care.

If you believe all (heck most) PHP developers care that it's a fractal of bad design, then your view is way too narrow.


I think this quote sums it up: "Do not tell me that “good developers can write good code in any language”, or bad developers blah blah. That doesn’t mean anything. A good carpenter can drive in a nail with either a rock or a hammer, but how many carpenters do you see bashing stuff with rocks? Part of what makes a good developer is the ability to choose the tools that work best."


  > "Part of what makes a good developer is the ability to 
  > choose the tools that work best."
Is an article that insults the intelligence of PHP developers best tool for convincing them to switch languages?


Okay. You want a piece of blog software. It has to have SEO plugins, Facebook integration, Twitter integration, fine grain editing controls, and requires approval for publishing.

Oh, and the client only wants to spend $1500.

What software are you going to use?

Many PHP projects are driven by momentum. PHP is a language to get things done in, and I know plenty of incredible PHP programmers who use PHP because it has unparalleled adoption and a library of off-the-shelf OSS software that can't be rivaled by any other programming language.

I'm pretty okay with people shitting on PHP, but shitting on PHP programmers is a completely different story. We use PHP because it gives us a leg up that no other programming language currently can.

Unless you've only been a programmer for a few years, you'll understand the libraries matter more than the language when it comes to writing software. In that regard, and with regards to the OSS software written in PHP, it probably comes close to or beats CPAN.


Ruby and Python are increasingly invalidating this argument. Python has some of the best diverse library support of any modern non-Java language. And for web stuff (which is basically all PHP does anyway) ruby is basically there. Yes we don't have an out of the box CMS aimed at the WP market yet but that just means someone needs to make it. I've worked with WP a lot and I understand why people do that and I don't disrespect them. I've also spent time staring at its guts and man they are gnarly. However if you're talking about designing new software (which is the situation you are in if you are talking about software design patterns like singleton) then choosing PHP because you are comfortable with it is a cop-out.


It's interesting that you mention this: "Yes we don't have an out of the box CMS aimed at the WP market yet but that just means someone needs to make it." I've got 3 "generations" of developer ecosystems under my belt[1][2][3] and from that experience I'd argue that the nature of PHP developers lends itself to creating a commonly-used CMS more than the nature of Ruby developers. I've seen the same thing happen in [1] and [2].

Ruby developers by nature are a lot more experienced and experienced developers like building great architectures and they tend not to be satisfied with "it works, but it's nowhere near perfect." So instead of a few CMSes we get many, and none get enough critical mass. In the PHP world ironically people are more focused on getting something to work even if it's not perfect because they don't even understand perfect. And they are more apt to use somebody else's im-perfect work. I'd argue that's one of the several reasons WordPress has managed to establish itself as the overwhelming marketshare lead for simple web CMS. And that reason is a necessary although by no means sufficient to explain WordPress' dominance.

[1] Clipper for DOS [2] Visual Basic for Windows [3] WordPress for the web

In summary Ruby is great for custom systems needed for SaaS but I highly doubt a single CMS will emerge to unseat PHP-based WordPress from it's throne. And end users don't give a crap what it's developed in or the superiority of it's technical architecture; all they care about is "Does it work for me." And PHP-based WordPress does.


First, no, PHP has arguably the worst OSS library support of all the "major" languages, when you consider the quality of the libraries. Second, this does not really negate anything I said. You can say a lot of good things about PHP -- it's convenient, it's available, it's easy -- you cannot say with any seriousness that it's well-designed. My point is that I can't take seriously a conversation about software design that is couched in PHP. The design of that language and ecosystem is shit -- I mean, do you even have a way to create virtual environments that doesn't require spinning up a new VM?

There is no way that PEAR/PECL can be reasonably considered more comprehensive than CPAN or PyPI, I don't even know what your frame of reference would have to be in order for you to think that.


If someone's talking about PHP and they don't mention composer or packagist (and instead bring up PEAR and PECL), it becomes immediately clear that they don't know what they're talking about.


Nice. We've gone from "but other people have already done so much with it" to "you don't know how to use it." Who cares -- my claim was that it's designed poorly.

I did, after all, say that I haven't used it in years in a nearby post -- I will gladly admit that I don't know much about the recent developments of a POS ecosystem like PHP. I also told you that none of this is related to my point, but hey, have fun using Blub, I never said you can't be very productive and perhaps even successful with it.

You're just not going to change any reasonable minds about whether or not PHP is well-designed, which is why your argument is basically of the form of "but it's already there!" and not "but it's so good!"


When I see WordPress I think this, but not PHP in general: haven't you used any frameworks? Unless you're KTLO who actually would build any web/service and not use a framework?

There are plenty of good frameworks out there for PHP that allow you to write clean code. Most of them have only existed since PHP4+. I understand where you are coming from, but in reality when you're writing about software design language is generally a moot point.


> Downvote away -- I know I deserve it, but I need to say this

I'm curious to know why you decided to post something that you knew should not be posted? If anything, it suggests that any advice or commentary you add is equally worthless because your standards are poor at best.


It just says that I talk for reasons different than those the guideline authors would prefer to motivate people to comment. In this case I was having a specific emotional/rational reaction, which I was sure other people were also having, and wanted to start a discussion around that tangent.

I'm not sure that your conclusion follows, either. How are my standards poor? And how would that render all advice and commentary worthless? Suppose -- to reduce your claim to absurdity -- that I had posted a proof that P == NP. It would have been totally irrelevant to the thread, but hardly worthless.


There is another argument against singletons. They destroy design information:

http://michaelfeathers.typepad.com/michael_feathers_blog/201...


I am not a big fan of "getInstance". For a session it should be named something like "defaultSession". It is perfectly reasonable that you later want to add a separate session that requires HTTPS only cookies, in which case it could be called "secureSession".


If we're on the subject of anti-patterns, should GOTO really never be used, in any situation?

I remember writing some code in C a few years ago and I needed a place in a function where cleanup is performed, and in case there were errors caught in multiple places before you get to the cleanup area, I used a goto statement to jump there after printing the error message and turning on a special error flag.

How would you solve that problem without goto?


Without goto, you'd either introduce a bunch of unnecessary functions or do this:

  init;
  do {
    stuff;
    if (fail) continue;
    morestuff;
  } while (0);
  cleanup;
Which I've seen in real code released to the public. Whoever does either of those things instead of just using a goto should be flogged in the town square.

edit: Other usually-bad alternatives to goto are the pyramid-of-nested-ifs or a set of running "bad" flags/enum that disables each operation downstream of the error until the cleanup is reached.


"Never" is probably wrong; there are almost certainly cases where GOTO makes sense. More likely than not, though, is that if you find yourself choosing between GOTO and writing something complicated and hard to read, the problem is that your language is not expressive enough -- you are trying to do something that your language makes it hard for you to do.

In the example you gave, the problem is that C lacks something like exceptions and that there is no automatic way for cleanup code to be called. In Java, you can use try...finally, and so you can put your cleanup code in the finally block, and other languages have similar constructs. Unfortunately, in many languages, throwing an exception from a finally block will cause one of the exceptions (often the first) to be "forgotten," which is probably a bad thing; this is also hard to deal with in C, however, since an error that occurs in your cleanup code would need to be signaled somehow, but you can only return one value from the function -- so would you return the error that triggered the cleanup, or the error that resulted from the cleanup?


>so would you return the error that triggered the cleanup, or the error that resulted from the cleanup?

That's a good question. Fortunately, I don't do anything complicated in the cleanup zone - mostly closing handles and freeing memory.


"Fortunately, I don't do anything complicated in the cleanup zone - mostly closing handles and freeing memory"

Closing handles could cause an error! Take a look at the close manpage; there are three error conditions:

* The argument is a bad file descriptor

* The call was interrupted by a signal

* An I/O error occurred while reading or writing

Reading or writing? Yes, as it turns out, closing a handle may involve I/O to perform the last synchronization of the file.

It sounds like you would ignore errors caused by closing the handle, and you would signal whatever error caused the cleanup to be entered.


GOTO should be used when it makes the code less repetitive, easier to follow, and less error prone. One alternative is to encapsulate the state of various resource allocations, and then call a single cleanup function at every exit point from the function that uses those resources (or take advantage of RAII, if supported by the language). However, in C this is cumbersome at best, and error prone at worst. Using GOTO for a common cleanup point is a perfectly valid use of the keyword.


GOTO in a C/C++ world is actually a fairly efficient way to manage the exit points of your function. If you're carefully managing memory, putting all of your method cleanup code in one place and directing logic there with a GOTO is more efficient that releasing memory at several different locations within your method.

At the same time, if your methods are complicated enough to possibly require multiple exit points, I'd argue that they should be refactored and broken apart a bit more.


This is one case where a GOTO is acceptable - branching to a common exit, if it makes the code more understandable.


You would put the cleanup code in a separate function, and call it.

I don't think there's anything wrong with using goto in such a case, though, if it makes the code more understandable.


Having worked in a large C code base that was occasionally tainted with this approach (rooted only because people have been told to avoid goto as dogma), I have to say that goto is a better approach to emulate try-finally or RAII in C. For one, the goto will read better as a single piece of prose, there will be no need to glance over at some other function to see the free call. Second, let's say your function has 2 allocations and a lock acquisition - that means your cleanup function needs a pointer to each, usually done with parameters. Add an extra allocation? New parameter to the cleanup function. This gets messy, fast, in a way that the goto does not.


Just putting the cleanup code in a separate function doesn't solve the problem. In C, goto can be used as a kind of fall-through mechanism to clean up all of the resources a function has acquired (but no more!), in the opposite order that they were acquired. There really is no other way to accomplish this without horrible if/else nesting, which for complex functions would be pretty ridiculous.

[1] http://eli.thegreenplace.net/2009/04/27/using-goto-for-error...


"How would you solve that problem without goto?"

I wouldn't bother trying, at least in C.


My problem with most singletons is that they are a half-way solution for a developer unwilling to commit and accept that sometimes a bit of global state isn't the end of the world.

Static fields and static methods on classes should be used sparingly, but if you're going to use them, just use them. Why half-assedly try to hide the fact that you're using them by wrapping them into a singleton?

This is a(nother) thing I like about Go, the design of the language allows for the fact that sometimes a function is just a function and doesn't need an object receiver and maybe it even modifies a package level global, so what? Just make sure you properly handle multithreading situations. In Go code you don't find a lot of patterns where people are trying to sweep what they are doing under a rug in order to not anger people who accept "common wisdom" code design guidelines as absolutes.

If you need to write "dangerous" code (and sometimes it is best to write "dangerous code"), do it in the open, out in the light of day, that way at least it can more easily be reasoned about if someone does hit a snag in it.


"Why half-assedly try to hide the fact that you're using them by wrapping them into a singleton?"

I may be misunderstanding your context for the above comment but when I use singleton classes for WordPress plugins I do so to avoid potential namespace collisions with other WordPress plugins.


Singletons are easy to implement, simple to understand and have no performance penalties. They don't need to be defended. If they work for your project, use them.


> Singletons are easy to implement, simple to understand and have no performance penalties.

Unless there's any concurrency to the system, that is. Then they're shared state (as fraught with peril as any shared state) except they're shared state which can be broken/corrupted straight from the initialization.


So Eric is sort of right although he doesn't explicitly state it: Singletons may provide a decoupling point nearly identical to dependency injection when designed with care. But that's not really the problem, and he stops with an argument that is compelling to someone in 2002 but not so compelling for someone from 2012.

The reason we prefer non-singletons to singletons are as follows:

• Most languages do not provide very good ways to prevent singleton collision. As software has become more complex and open source's success increases the size of the average dependency tree, this problem is exacerbated.

• Singletons force you to confront all the problems shared state concurrency has to offer, with almost no support. DI objects tend to be isolated from one another and do not run into that level of complexity so soon.

• Singletons tend to make it harder to test code unless your language has a method for overriding or mocking singletons within a dynamic scope (or static type checking between types with liskov-substitutable signatures). The most classic exampe of this is one of the most prevalent singletons: your system clock.

Knowing what we know now about how successful software projects tend to be confronted with expectations of concurrency, parallelism, robustness in the face of reuse, and testability; singletons offer a lot of costs for very transient benefits.


Singletons also make things painful if (when?) you have to go from "one instance" to "two instances", which regularly happens.


Which is why they should be used sparingly, if at all. I'm not advocating we go out and start making every class a singleton, just explaining how they do serve a purpose in PHP/WordPress development.


I support Eric here. Singleton make sense in WordPress specifically for encapsulating plugins. In WordPress plugins can never have more than one instance so it's really a moot point to expect them to be anything else.

Outside of WordPress plugins, I don't currently know of cases where I'd also advocate for singletons. Yes in most other cases singletons are bad but I'm sure there are some other cases where they do make sense. And you can't prove a negative.


In the case of WordPress plugins which is what Eric was writing about you know they never will go from one instance to two.


I generally prefer Lisp-style ✲dynamic✲ variables. They basically work the same way singletons do, but they can be set and reset at a block-scoped level (great for test mocks and the like, and makes your control flow easier to understand), and they play much better with threads.

Rust doesn't even have singletons or global variables, since they aren't threadsafe. It has thread-local storage, which dynamic variables are built on top of.


> It has thread-local storage, which dynamic variables are built on top of.

That hack only works if execution can never be suspended though. The issue exists in Python where it's possible to fake dynamic scope using threadlocals, but that can blow up if execution is suspended (between `yield`s in a generator, for instance) as the stack doesn't get unwound (merely frozen) and the threadlocal isn't reverted if it's in the frozen part of the stack. Same deal if it's possible to unshift stack frames, the threadlocal will more than likely end up in the wrong state.

An other thing which bothers me with threadlocals is that it's not really possible to introspect currently-bound locals in order to "save" them alongside lambdas (though that may be an API issue more than an issue with the locals themselves), and in my experience async callbacks tend to need their creation stack context more than their callstack context.


Both good points. Rust doesn't have the problem with execution being suspended, since the only mechanism for suspending execution is through the task system. Thread locals are all per-task.

The issue with introspection is fair, and it's a gotcha you have to keep in mind whenever you use dynamic variables. They're necessary to make the task system and condition handler system work under the hood, however, so we can't just remove them.


> They're necessary to make the task system and condition handler system work under the hood, however, so we can't just remove them.

Oh I've nothing against dynamic variables at all and wouldn't want them (or conditions) to be removed from Rust (in fact I wish solid dynamic variables were available in more languages), don't get me wrong.


This is a good read on singletons.

http://www.object-oriented-security.org/lets-argue/singleton...

"Singletons are possibly the single greatest obstacle to good object-oriented design today. They are often at the root of huge intractable design flaws in large systems, and yet many programmers continue to use them and even insist that they are a good design pattern. Many programmers point to the fact that the singleton pattern is a prominent part of the book Design Patterns, but don't realize that at least one of the authors of that book (Erich Gamma) is on record saying that it shouldn't have been.

We argue that Singletons are almost always bad design and almost never needed. In the few cases where singletons seem necessary, the "environment pattern" offers a reasonable alternative. Therefore, we recommend that programmers always avoid singletons and that programming languages ban them or at least provide an option to ban them."


I prefer to mix both dependency injection and singletons for the best of both words. Classes accept dependencies in their constructors but as optional parameters -- if the parameter isn't provided, a default reference is pulled from a singleton.

It saves a lot of extra typing when 99% of the time your dependencies are fixed.


Singletons, globals/statics, and dependency injection all seem to be solutions to the problem of making objects find each other at runtime.

Maybe it's time for a dedicated language feature to solve that problem? For example, each object could carry an implicit reference to an "object pool", from which it can fetch other objects by their class/interface. If an object constructs other objects, the "pool" gets passed along implicitly. Test suites could use "pools" filled with mocks. And unless I'm missing something, the presence of all required dependencies could be statically checked at compile time.

Basically it would be like Lisp's dynamic variables, but based on the construction hierarchy instead of the call hierarchy. What do you think?


The main issue I have with singletons is that any mutable global state prevents your application from being first-class within its own runtime environment.

This is of course useful for unit testing, but also reduces hidden state dependencies between submodules.


I've been of the opinion for a while that static variables of any kind should be avoided except for const data (tables, constants, etc.). They make code very difficult to impossible to port to multi-threaded environments, and make it hard to cleanly instantiate and then clean up a module within a larger program. Even things that feel like they should be global should be contained with a global context container that can be cleaned up.


I agree. But remember, the article is specifically about singletons in WordPress, which is written in PHP, which is single-threaded.


> the article is specifically about singletons in WordPress

Is that why you open with

> I would argue that Singletons are not just useful, but are necessary for robust software development.

?

No mention of wordpress there, you use it as an example but your assertion is that singletons are downright necessary to software development.


@eamann, I gotta give @masklinn credit there, you didn't explicitly make it clear your post was focused on WordPress-related use-cases. It was obvious to me from your references and knowing your focus but maybe not obvious to those who don't specialize in WordPress if all they did was scan the article, as most people do.


No, even reading the post it's not obvious. It's obvious that he talks about wordpress, but considering the assertion I quoted I simply read it as using a wordpress-based example/use case to support his hypothesis.

At no point did I find or notice a modifier of the article being an argument for the usage of singletons in wordpress plugins. though I may just have missed it.


I can't speak to server side development, but for ui applications, storing your models in a singleton can save you a lot of time. When you're developing apps its very easy to get stuck in a mindset that you only need certain data for each screen, but the truth is the data for one area will inevitably bleed over into other areas, and having a good way of updating and reflecting data to the areas needed is the sign of good architecture.


I've posted a follow-up to this that broadens the ideas of Singletons for general PHP use. Using abstract classes and inheritance, it's also possible to unit test the code contained within a Singleton. The follow-up is here: http://news.ycombinator.com/item?id=5023027


Is it just me or did he never actually address the dependency injection complaints? It read like he spoke glowingly of how dependency injection decouples your code and makes your blissfully flexible and then nothing. Was his counter argument just that sometimes you need to be less flexible?


He tried to, with the suggestion that with DI, you suddenly had the dependence hard coded and would have to make a code change to change the dependency. This, of course, is not accurate.


> Think of every time you’ve used the global keyword when working in WordPress.

I pretty much stopped reading there. Referencing WordPress when making a point about software design does not strengthen your point.

Singletons are the antithesis of dependency injection.


The number of replies defending PHP make me think that HN is very close to becoming a useless place, dangerous even, for obtaining programming (and probably other) advice.


It's not about defending PHP. PHP is an ugly, inconsistent language. It's a matter of pointing out why certain tools are used in certain environments.


     $this->persist
That's just sad. And the author even is a wordpress developer


Yes, it's sad. And no, I'm not a "wordpress" developer, I'm a WordPress developer who didn't properly proofread everything before publishing. You should probably take a lesson from that ... :)




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact

Search: