What problems can a global state entail?

Asked

Viewed 1,026 times

33

What problems can a program face with the use of global states?

Where can it be acceptable? That is, how to know if I am abusing the resource?

What alternatives exist to avoid this?

I’ve already gone over the subject in question Why shouldn’t we use Singleton? and somehow prompted this new question.

  • 2

    It’s not duplicate. Global status and global variables in Javascript are different things. The problem is much more complex than the one addressed in the other question in a specific way. The answers here if given there would not make much sense and the answers posted there would explain part of the problem and in a way that does not fit here. http://meta.pt.stackoverflow.com/questions/607/lidando-com-perguntas-duplicadas/609#609

3 answers

22


TL;DR

The problem with a global state is that most of the time you discover that it shouldn’t be so global.

A global variable is like a dark alley that you use as a shortcut to get somewhere more easily, but you never know when you’ll be surprised by something unexpected. ;)

Problems with variables and global states

Using variables to share data

Many developers use a global object or variable to share something between different components of a system.

This is done either by laziness or by failing to adequately structure the dependency relationship between components so that they can more adequately limit the scope of what they want to share.

I’ve seen several cases where the developer decided not to use parameters, so he made a logic like this:

var valorGlobal;
function rotina1() {
    valorGlobal = 1;
    rotina2();
}
function rotina2() {
    alert(valorGlobal);
}

The equivalent with the use of parameters is:

function rotina1() {
    rotina2(1);
}
function rotina2(valorLocal) {
    alert(valorLocal);
}

As you can notice, the chance of some error on the part of the developer in the first case is much higher.

Code spaghetti

Continuing with the example and several methods start using this global variable, sooner or later the code will be indecipherable.

For example:

var valorGlobal;
function rotina1() {
    valorGlobal = 1;
    rotina2();
}
function rotina2() {
    valorGlobal = 2;
    rotina3();
    alert(valorGlobal); //qual o valor aqui?
}
function rotina3() {
    valorGlobal = valorGlobal + 1;
}

The abuse of global variables seems to cause an effect similar to the indiscriminate use of goto. You simply get lost in the order of execution and what the code really wants to do.

Competition and performance

Think of the above examples performed in parallel processes. It would be the chaos on earth!

Changes to global variables are problematic because they need to be synchronized. But synchronization costs expensive and can create bottlenecks in a system multithreading.

The more limited the scope of states, preferably a single object, the more efficient the code.

Scope, scope, scope, scope

At the beginning of a project, when there are still few classes, code, functionalities and, consequently, little confusion, encapsulating data seems unnecessary. Therefore, global states are extremely tempting to be simpler to implement.

However, in the course of the project, what is usually discovered is that it will be necessary to repeat a lot of code because what is already done has been "tied" with global variables and new functionalities require new global variables.

In short, it turns out that what at first seemed to be useful to the whole system is actually not. The scope needs to be limited, but the use of global variables does not allow this.

That’s pretty close to what it was discussed about Singleton. For example, if we have a routine that saves reports in a folder whose configuration is global and now it is necessary to save only one of the reports in another folder, we will have to change the existing routine or duplicate it.

When global variables are useful and necessary

There are cases where it is really necessary to use global variables.

The most obvious case I can think of is for the development of frameworks or libraries.

Frameworks usually break several Object Orientation rules (à la Matrix), such as changing private attributes of objects and maintaining many global states.

A Dependency Injection framework, for example, must maintain a global map with the dependencies it manages. The difference is that this mechanism will be extremely well thought out and tested.

Completion

The use of global states should be avoided at all costs in development considered "normal", that is, it has to do with the ordinary functions of a system.

However, for non-functional functionalities, frameworks and libraries, which implement very specific use cases, usually have well-defined scope and are developed by more experienced people, the use of global states is acceptable and sometimes even necessary.

11

Complementing the utluiz response. I’m not saying great news, just a different way than what was already said in the other answer and adding something.

Confusion of design

Global state can only change its state by destroying the previous state. It is not possible to create a new state. With instances you can, if you wish, create new states for something related. You almost never knows when it will need different states at the same time.

A change in the design of one part of the application may require a change in the global state that may generate need for change in other or even all parts of the application.

And the change of state hinders the understanding needed to make the changes.

Note that many states can change in unpredictable ways. The global state is only slightly worse because the source of the change may come from more distant sources.

Making the state more local obviously does not solve all the problems of design.

Testing

It just makes testing difficult. Some say it’s hard to test using global state because you can’t change how you access information. This is not true. It is possible replace the overall state (Singleton or not) with a testable shape. The problem seems to be another and perhaps worse.

Of course, the fact that the global state may eventually have its state modified unpredictably in the application running in production can render tests in a controlled environment useless. But this is a problem in itself. It doesn’t just affect the test. State changes from anywhere, unpredictable, cause bugs whose tests can’t pick up. It gets hard to trace an error even thrashing in production, imagine in a controlled environment that fatally will not reproduce the same flow.

Difficulty to use

Global state makes the API a bit magical. You need to know things unrelated directly.

It prevents the creation of pure functions when this is desirable. Pure functions cannot avail themselves of states external to itself.

If you prefer to have instances, it is possible eliminate the competition. In addition to the cost of blocking processing, errors caused by competition are well, well, much harder to find.

There is inherently global state

But there are situations whose state is inherently global. Can you imagine having instances that hold the string of PATH operating system? Or system time? This holds for any configuration that can only exist one and only one. For information that is universal, semantics dictate that you only have one. For information that would become useless if one day there were different states.

Some people will say it is better, even in this case having instances to facilitate the test. I think just making it easier is little to justify creating an instance where the state should be global. Being harder doesn’t mean it’s unfeasible. And of course some less dogmatic languages make it easier than others.

Care must be taken not to start with a global system configuration and one day realize that it should be a per-user configuration. But it is likely that you have a problem of design more serious than the problem of being global or not. Even if you had this state in an instance your application is probably not prepared to understand the shift of the configuration to another level.

You can’t abuse a resource but if there really is a benefit, if you have experience and sure that it won’t cause future problems, there is no better solution, use the global state. It’s like the drop, should not use until it is useful.

How to avoid problems with global status

  • Use parameters of the function.
  • Do dependency injection. It is nothing more than the parameterization of the object instead of the function.
  • Prefer immutable global state.
  • Prefer a Singleton, preferably immutable, with global data.

This last case is interesting because you keep the global state by solving the majority problems, especially if the data are immutable. No competition problems, you can test (yes, you can mock), the design can be modified more easily to accept a different instance instead of the Singleton, just do it more generally, but this is another matter.

I take this opportunity to show that there is abuse in design of the application because of the test and gives to test using a design pattern instead create a new problem in the application.

1

Where is acceptable? Perhaps necessary?

Blackboard system (here) is essentially a system made up of several components that share a common knowledge base, or what has been called a global state. If you implement one, then you will have to make use of global state, and this does not mean some deficiency of the design of the software in question.

Often, when we speak of "global state", or "global variable" as undesirable elements, we are referring to the accidental complexity, that is, the one introduced not by the domain in question, but by the option of design of the designer.

An additional comment can be found at Why using global variables is not a good practice?.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.