5 ms·
I see this argument pop up from time to time and it confuses me. It's almost as if someone read "global variables are evil" and understood it to mean "global da
by sago 12y ago
I see this argument pop up from time to time and it confuses me. It's almost as if someone read "global variables are evil" and understood it to mean "global data is evil".
Singletons aren't global variables. Neither are service locators. Nor databases. Nor screens. Nor keyboards. Global variables are global variables.
Unless they all are. And if you're going that way, you have a single main function, somewhere.
- kaens 12y agoWhen people are referring to global variables these days, they would often be more accurate in referring to "global mutable state". Singletons can be this, service locators can be this, databases can be this. This can be bad, notably when assumptions are made about the state without taking into account that you're not the only one that could be changing it. Depending on what's changing, this can lead to very confusing / seemingly unpredictable behavior. Another way to put it is that the nature of the issue with "global variables" is often present in the things you mention.
- Silhouette 12y agoI agree with your basic point, but I'm not sure you even need the mutability requirement to capture one of the underlying issues: you have an implicit dependency on something elsewhere in the system. Even if that something is constant, or at least constant during any particular program run, it still means you can't change the code that sets it up without checking your entire code base for unintended consequences. From this point of view, mutability just makes an existing fundamental problem worse, though it introduces new problems as well.
- sago 12y agoWhy is it implicit? The point is that it is much more explicit. And use of SL doesn't create a dependency that isn't there otherwise. The dependency will be there anyway, because bits of code do depend on one another. The point is, do you want those dependencies to be managed by another piece of code and another piece of configuration? Or is it better to say what you need in the code where you need it? I'm not religious about it, there are times when being implicit is better, but often it is dramatically more complex for no obvious benefit.
- Silhouette 12y agoWhy is it implicit? Because if we have module A depending on module B via some clearly defined interface, but in fact the behaviour of module B also depends on global module C that is set up elsewhere, then B's interface no longer fully describes what A can expect. If C's scope were limited to what's happening within B anyway then this would just be an implementation detail. If C were given to B as some form of explicit dependency by A, then it would be a specified part of the interface. However, if C effectively has global scope by any mechanism then there is now an implicit interface to change B's behaviour that A doesn't know about. Developers reading or maintaining the code for A, C, and anywhere else that can affect C if it's mutable, then need to be aware of what each other are doing, and changes to any of these parts of the code potentially affect any of the others. (I'm not going to address your other point, because I didn't say anything about service locators in the first place.)
- kaens 12y ago> I'm not sure you even need the mutability requirement to capture one of the underlying issues I don't think you do either, although if it's a globally accessible constant throughout a run, problems with inconsistencies only tend to crop up if the value is being used to determine behavior -- which you might need to check for, as you mention. I'm not sure if global mutable state is the same as the problem you point out though -- they do share a similar nature in the framing of dependencies, but they cause problems for different reasons. Also, mutability tends to be able to be a real problem in systems much smaller than ones where problems from abuse of global constants start to rear their heads.
- Silhouette 12y agoI'm not sure if global mutable state is the same as the problem you point out though -- they do share a similar nature in the framing of dependencies, but they cause problems for different reasons. I agree, there are (at least) two distinct problems here. One is the existence of any implicit dependency because of global (or other broad) scope. This can create surprising spacial interactions in the code, making it harder to maintain. Another is the existence of mutable state. This can create surprising temporal interactions in the code, also making it harder to maintain. Loosely speaking, the danger from these effects multiplies.
- vonmoltke 12y agoI'm not following what you think you are avoiding and how you think you are avoiding it. For example, I used to work on radar signal processing code. We had several global constants that were used in various calculations in the processing pipeline, one of which was the speed of light at various altitudes. Regardless of the manner in which these constants were inserted into the program, changing one of them was going to have direct effects on several calculations and ripple effects on others. It is just the nature of radar equations. Thus, if you have a program that has an immutable global constant it is likely in the same situation. How do you ever change that value in any way without retesting everything to see what the effect was?
- Silhouette 12y agoThus, if you have a program that has an immutable global constant it is likely in the same situation. I don't accept your premise. Firstly, constants are used for all kinds of things, from hard mathematical data as in your example to configuring connectivity with external services via particular database details or URLs. Secondly, while some programs really do only have one main purpose and so some of the background/context data really is almost globally applicable, this is certainly not always the case. In particular, the larger a software system becomes, the less likely this is to be true. How do you ever change that value in any way without retesting everything to see what the effect was? If the value doesn't have global scope, you don't have to retest everything, only parts of the system that can be affected by the change.
- sparkie 12y ago"Global variables" is really language specific terminology for global data. What I mean by "globals" in the scope of testing is "side-effects" - anything which can affect the behavior of some unit which you're trying to test beyond the test target and the values contained in your test. All of your listed "non-global variables" are examples of it - they make it more difficult to perform isolated unit tests because you need to bring the global state into the test, then you're no longer performing unit tests, but whole systems tests. A database is a good example. One might have some class "Person" with some business related logic in it. If your goal is to simply test this business logic of a person, then why would your test be concerned about whether it can establish a connection to a database? By definition, this is no longer a unit test, but a systems test, and the test surface is much larger because now you need to be concerned about whether or not a connection can be established and myriad of other possible problems, all of which could be tested separately, and by knowing which tests succeed/fail, we can have immediate feedback on where some problems might exist, rather than having to debug an entire system to find an issue. In the case of the service locator - you can't really perform "unit tests" on individual blocks of code which have dependency on the SL, because the SL is mutated in arbitrary places througout the codebase. The SL acts to increase coupling, because now instead of depending on just a specific interface, you depend on the whole runtime data of your application.
- sago 12y ago> "Global variables" is really language specific terminology for global data. Strange, I thought it was terminology for global variables. > What I mean by "globals" in the scope of testing is "side-effects" Which is as whole different kettle of mackerel. Minimising side-effects is, of course, excellent advice, and can help with testing. But global variables and SL are not the same thing as side-effects. Your example (of testing a database) seems very confused to me. You're talking about coupling now. Not global variables. Why would you suddenly need a database connection? Why does the existence of global mutable state mean that nothing in your code can be tested independently? You seem to be imagining the worst case of coupling as an argument against service lookup. The last paragraph seems blatantly false. You're again straw manning this version of an SL that is mutated in arbitrary places through the code-base and therefore can't be tested in isolation, and neither can the components that use it. That is a strange version of SL you have here, and one that DI wouldn't help with.