1. 28
  1. 37

    And the Design Patterns book was never meant to be prescriptive: it’s not telling you what to do, it’s describing what people have done.

    I will upvote any article that includes this sentence.

    1. 4

      This sentiment altered how I represent my experience in presentations, even if it diminishes my authority to score some modesty points. I want to present my thoughts as a model: given these inputs, I made this decision. Given the same inputs, I implicitly — or, if I’m adamant, explicitly — recommend that you make the same decision. If anything is different, please revisit my thought processes to see if the variables are sufficiently divergent to warrant another strategy.

      This helps me avoid being overly opinionated while remaining confidently correct.

    2. 17

      This was more language-specific than I expected from the title. It’s more saying, “Implementing singletons by modifying class instantiation behavior in Python is a bad idea, so here are some better ways to do it in Python,” than, “The idea of singletons is inherently bad.”

      1. 6

        I see it as a general argument against singletons which happens to be presented via Python code examples. Switching the language wouldn’t change the core argument, which is that singletons conflate “this class models that kind of thing” and “here’s a limit on how many instances the program is allowed to have of that class”.

        1. 2

          The author themselves tagged the article as python, which is why I suggested adding the same tag here. This is about as language agnostic as the article gets:

          The first problem with Singleton is that it encourages you to mix together two different ideas into one class.

          Even that statement assumes the paradigm in question is a class-based paradigm. Singletons are possible in non-class paradigms as well, which this article does not address.

          Miško Hevery wrote a similar article, singletons are pathological liars back in 2008. His premise was basically the same: it creates too much confusion between the class instance and the class itself. Shortly after that, he designed AngularJS services as singletons, probably assuming that he sidestepped the class/instance problem by making users define singletons in factory functions that his framework would run only once.

          As it turns out, the main problem with singletons is that they are basically global mutable states. For those who haven’t been bitten by global mutable state, the problem with it is that it erodes separation of concerns and creates situations where bugs caused by undesirable mutations can’t be traced because the mutations occurred in some downstream consumer of the singleton e.g. as a property assignment. One can’t really set a breakpoint or log anything in such situations, so diagnosing them often requires a great deal of searching. Subsequent front-end frameworks rightly went to great lengths to avoid such singletons. Elm and React went so far as to replace the application state entirely in their update processes.

          The rest of the article is pretty Python specific, from functools to the details of which value types are mutable and which are not.

          1. 1

            I don’t think the conflation is inherent in the concept of singletons, though, and it doesn’t show up as often in other languages. Taking Java as an example, a very common way to do singletons is to define an ordinary class with an ordinary constructor, where the class contains no logic whatsoever about enforcing a single instance, and rely on a dependency injection framework (Spring, Guice, etc.) to call the constructor and pass the instance to classes that need it.

          2. 4

            I think the context that you (and I; I am inferring from his description of Singleton) are missing, is: the definition of the Singleton pattern is about defining a class such that whenever it is instantiated, it returns the same single object. In other words, a singleton is not an object, it’s a class and an object.

            I have never heard of this definition of singleton; I tend to use the lower-case s form of the word to mean ‘a single global object’. It seems insane to me that you would denature a class to the extent that instantiation is not actually creating new objects. But it does seem like the sort of nuttiness that our OO-obsessed forebears would have got up to and I’m thankful to Ned for telling us never to do it again, if so.

          3. 14

            Something I’ve just realized: the positive, actionable form of “singletons are bad” is “capabilities are good”. Less abstractly, just pass the darn thing as an argument :-)

            1. 4

              Indeed! See http://www.object-oriented-security.org/lets-argue/singletons for a take on singletons from the author of Cap’n Proto.

            2. 6
              1. 4

                I think singletons like many other patterns tend to have the problem that people simply use them because they have learned about them and not basing the decision on actual need

                Singletons can be used in more situations than make sense, so they are used in more situations than make sense.

                I think we see different variations of this elsewhere too. We see that with cloud computing, kubernetes and docker, we see that with blockchains where a normal database would be enough or better suited, we see that with big rich client JavaScript framewkrks when all we do is displaying a bit of text.

                I think the solution to all of these and many more is being more concerned about what is actually needed or what the goal really is rather than what it could be. As the devolper it’s easy to see what is possible and that might be a small thing like “we could make this a singleton” or a huge thing that changes many lives and everything in between. I think that sometimes we forget taking a step back and look at what we’re actually trying to achieve here and choose tools, including patterns accordingly. Not everything that can be fine should or must be done, even when it might make a lot of sense in certain cases.

                1. 3

                  The whole idea of enforcing some developer in the future from doing X by means of gimmicks inside the code that they will control, is a rather stupid one per se.

                  Not limited to singletons. Whenever someone claims “because it forces you to…”, We know almost for sure that some non sense will follow.

                  The article does a good job debunking those silly old questions. Decades have passed since design patterns and I still don’t get why someone would create multiple instances of something of which they only want one instance. Feels so detached from reality. A programmer doesn’t sit in front of the screen accidentally doing arbitrary things.

                  1. 2

                    The prevalence of singletons is a side-effect of an under-realized developer experience for code linkage. It should be possible to make something a singleton for some specified extent of code, such that all the drawbacks of singletons are avoided. That is, I should be able to program some subsystem assuming a dependency is a singleton, but substitute an alternative implementation in test code, or override it for some background job, etc.

                    1. 6

                      I think Scala’s implicit parameters are an implementation of this idea.

                      Personally, I don’t mind passing the context explicitly. It’s more tedious to write, but makes dependencies clearly visible, and provides friction against making functions depend on too much of their environment.

                      1. 4

                        Scala’s implicit parameters are an implementation of this idea

                        Yeah, especially in Scala 3, where most of the sharp corners of implicts have been fixed..

                        I don’t mind passing the context explicitly.

                        It’s usually fine, but it requires typing (like, physically on the keyboard, and also in the type-definition sense) and therefore discipline. It also introduces the “function coloring” problem, which can cause annoying refactors.

                        provides friction against making functions depend on too much of their environment

                        I think that we need tools for making this more explicit as well. For example, some syntax to deny access to portions of the context.

                      2. 1

                        I think .net DI system has a very elegant solution for this. You get an instance of what you need and the host setup decides the actual scope. So for example what you think is a singleton may be something scoped to the currently running unit test. https://docs.microsoft.com/en-us/dotnet/core/extensions/dependency-injection#service-lifetimes

                        If you want singletons, you can setup actual singletons this way too.

                      3. 2

                        Singletons are totally fine in other languages.

                        In the JVM world they are quite popular, for example in Spring the default bean scope is “Singleton”. In Kotlin they even have their “own keyword”: object {}. And they are also used in the C# world.

                        So I guess this only limits to python, and to a certain implementation.

                        1. 1

                          This is because Spring is dedicated machinery for dependency injection. Python doesn’t really have anything comparable to Spring that is widely deployed. In fact we don’t have a perfect analog for interfaces either. Absent Spring or a similar DI framework, you have to manage your singletons yourself, which leads to the issues discussed in the article. It isn’t so much a language issue as an ecosystem issue—if you were working in a pure Java context apart from Spring or Java EE, you’d either have to bring in another DI system as a library or do what’s being discussed here with Python.

                        2. 1

                          I think of singletons as a code smell. Why not just have two root objects?

                          1. 2

                            I tend to agree, and I’ve even heard it referred to instead as the “Highlander” anti-pattern (based on the Highlander sci-fi franchise with immortal warriors fighting each other and shouting “there can be only one!”). It’s weird to me to see how many people in this thread dismissed it as just Python not having good enough tooling for the good singletons of other languages…

                          2. 1

                            It is common to lump all application code into one type. That leads to the mistaken logic that a particular concept that is bad for one, is bad for all.

                            While true that singletons are (typically) bad when object modeling a problem domain or Abstract Data Type, they can be perfectly applicable to application infrastructure around that code, or within a development/runtime framework.