📜 ⬆️ ⬇️

[Archeology Live] Shameful talk about singletons

Audience: Java Junior, holivor lovers, professional singlton writers



Any comments and suggestions are very welcome. This is my first video, and it’s not entirely clear if you need such content here. Consider this a closed alpha test, only for visitors to the Java hub :)


Below is a full text transcript, who does not want to spend time viewing.


Introduction


Hi, Habr! The evening has come, and it's time for us to seriously talk. I want to discuss with you a shame. Singletons


The fact is that I constantly hear from acquaintances in the drinking bouts, how they destroy singles on the review code and mow down the spring because Spring is slag. And now my strength is no longer tolerated, let's clarify for all the garbage.


First about why singltons are embarrassing.


The oldest book in which it is said about singlton (well, at least, the oldest, which I saw with my own eyes) was written in 1994. This is the book Design Patterns of the Gang of Four: Gamma, Helm, Johnson, Vlissides.
Just think how old it is. What did you do in 1994? Some of our colleagues have not yet been born this year.



Or, the second love of my life is the book “Test Driven Development” by Kent Beck, written in 2002.



And this is what is written about singletons there:



I’m not telling this to shake the old days, but to show what a monstrous button accordion is the whole theme with singlet singing. Singles are hatile, when you were not yet born, or you were in elementary school.



Therefore, in principle, it seems to me that it is a shame to discuss singletons in public. You can talk about this only with your closest friends, with your beloved woman / man, and with you, dear Habr.


Bright side


It is clear that there are all experts, and the ass feel the danger of singletons. But the bum is not the best indicator, let's somehow verbalize our anxiety. What exactly are bad singltony?


Global state


Singleton is primarily a global state. You get one indivisible, poorly managed global skoup. This lack of control is a problem in itself.


To illustrate this somehow, imagine that you have some kind of state machine or communication protocol hiding inside your singleton. And if you want to automatically test it, then it turns out that a) you need to simultaneously test everything that touches the singleton and b) the worst thing is that these tests must be performed in a certain order.


If tests are obliged to be performed one after another, the unnecessary cannot be thrown out of them, then very quickly we arrive at a situation where one test run is done in at least 12 hours, and this is very bad.


Explicit and implicit


There is a well-known principle that the explicit is better than the implicit. This principle, by the way, is incorporated in PEP 20, better known as "Python Zen".



When you transfer objects not exactly to the address, but transfer them to the global state, you thereby hide the connections within the code. This is super implicit. As a result, the code quickly turns into magic. He somehow works, but by itself, and he is no longer in your power.


The Single Responsibility Principle


The principle of sole responsibility. That is, it is the letter S in the abbreviation SOLID. This abbreviation is the most important in the life of any javista. I respect her so much that I want to do a tattoo with her.


This principle was once introduced by Robert Martin (better known as Uncle Bob).



He argues that each object must have one responsibility and this responsibility must be fully encapsulated in a class.


If we do a singleton, then in addition to his immediate responsibilities, he assumes another task: managing his life cycle. It is no longer the calling code that decides how and when an object appears, it is not the usual environment that organizes access to it, but all this is pushed inside a singleton class. In a sense, he really performs this task, but it is crooked and wretched. Actually, like any code that tries to keep up with two hares.


Strong connectivity


All components using singleton, or God forbid - communicating through it, instantly turn out to be rigidly connected. Bound often have to unleash - for example, to write tests. And, to test the code, thickly smeared with singletons, is very unpleasant. Even a single singleton can seriously strain everyone: testers, TDD programmers, and podgadit on demonstrations of isolated functionality.


Java Specificity


In Java, there is no special way to record singleton. Therefore, there are many ways to write it, and they are all ugly.


First, everything can be crammed into a static field or enum.


public class Singleton { public static final Singleton INSTANCE = new Singleton(); } 

 public enum Singleton { INSTANCE; } 

But it will not be a lazy option, we do not need it.
Although enum can still be made lazy, if you want.


You can shove everything under synchronized:


 public class Singleton { private static Singleton instance; public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } 

But it will be the brakes, which actually symbolizes synchronized, in the most typical use case.


Or you have to use the double-checked locking option:


 public class Singleton { private static volatile Singleton instance; public static Singleton getInstance() { Singleton localInstance = instance; if (localInstance == null) { synchronized (Singleton.class) { localInstance = instance; if (localInstance == null) { instance = localInstance = new Singleton(); } } } return localInstance; } } 

He looks even more disgusting. Plus, the developers of the Java language expressed their attitude to this form of writing:


"There exist a number of common but dubious coding idioms, such as the double-checked locking idiom, that is, the proposed semantics. "


Dark side


And, as it were, all these considerations in plain sight. But there is another, dark side of the issue. There are other people more practical. They have their own standard answer: developers who are scrambling away according to Solid, on the Liskov principle, etc. are just theorists. In real life, everything is wrong, and in fact singletons are needed. And for this they have a special philosophy. Counter-philosophy.


Global state is everywhere


It is difficult to come up with a system that is not a helloWorld or a theoretical illustration, where a global state would not occur in the subject domain itself.


At a minimum, a global variable is our real world in which we all live. If we have some kind of computer game, MMORPG, we write it, then the single virtual world of the game is also a global state. We will not have another life and another world.


More locally, if you have a single database in the system, and this is part of the domain, then it often makes sense to attach to its uniqueness. Otherwise, there will be no time left to solve an applied problem, and everyone will start writing a management system with an infinite number of databases.


The argument about the order of the tests here also does not work: it is obvious that during execution, our only base should be raised first (and tests should be performed on the base), and then the application code. If you raise the code before the base, then everything will fall. Most of the projects that I saw, explicitly launched the database before the code, and did not see any practical problems in this at all.


"It just works" better than explicit


Modern software projects are extremely complex. Maybe these are the most structurally complex things, of all that humanity has done in its entire history.


And sooner or later, in your project there are thousands of classes, hundreds and thousands of dependencies on external libraries. Starting from a certain moment, you can’t manage them manually, smart build systems like Maven appear. Maven appeared, as far as I remember, from the horror that the developers met when building projects on the Turbine web framework.


Sooner or later, you realize that the system is becoming comprehensible. Its complexity is too great to fit into the brain of one person, even if it is the most important important architect. And you begin to look for such an automatics, which will itself think about internal connections, about indication and tracking errors, about automatic dataflow, and so on.


Obviously, such a system largely consists of magic. And in this case, magic is not something worth running from. On the contrary, it is worth striving for. But it must be good, high-quality, reliable magic.


Hard is better than soft


If the project is large and difficult to understand, direct hard links simplify the understanding of the code. In case of an error, the location in the frame will be exactly where it originated. Opportunities for building very simple graphs that reflect the structure of the code are opening up. Compare this with really weak code relatedness based on queues, when an error that took off in one place of a system actually needs to be searched on the other side of the queue, or several queues — such searches can take hours.


As for testing. If you look at how it is in reality, then in many projects testing is either not done at all, or done in a very reduced form. The project may be thousands of classes, but only a few dozen tests. And for the sake of this tiny amount, there is no point in worrying at all, and rewriting the system in a special way. This concerns not only singletons, but in general everything - the real full-scale testing draws a lot of additional conditions. In practice, putting testability at the forefront is not always a good idea.


Java Specificity


Yes, writing singleton looks ugly. But in the IDE, you can always create a template of the "ugly" class, and forget about writing this unpleasant code manually forever. As they say, darkness is a friend of youth.


Decision


And so, we are on the verge of a real conflict: some people want singletons (in fact, just a global state, they just call it singleton), and others - on the contrary, strongly against it.


An excellent solution is the transition from real singletons to smoker sigltons ... oh. Singleton Beans from Spring. What is the point: using Component and Scope annotations (SCOPE_SINGLETON) you mark some classes as singltons.


 import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @Component @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) public class Greeter { public String hello() { return "Hello World!"; } } 

Then in any place you can make a field, mark it as @Autowired, and at the start of the application in this field the required instance will appear.


 import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloWorldController { @Autowired Greeter greeter; @RequestMapping(path = "/") public String home() { return greeter.hello(); } } 

Note that this option solves all the problems listed above.



Summary


The issue of singletons has long been resolved. It is surprising that there are people who still do not know about it. The solution is Spring and other systems of inversion of control and dependency injection. Singletons do not need to mow, there is no need to het people who write them - they need to be translated into Spring and converted into our Spring-religion.


And further


And since you have not only watched the vidos, but also read it to the end. Thank you for absorbing my content, I was honored by this. (seriously.) And now what you need: be sure to leave a comment on this article, put a like, subscribe to the Java hub on Habré , to the blog of friends from JUG.ru who motivated me to post this hot brendump on the network, and other prominent video bloggers .


Until!



')

Source: https://habr.com/ru/post/335006/


All Articles