Have you ever been in a situation where an application’s state changes unexpectedly? Do you get stuck in a loop of trying to solve the errors and issues in the programs without knowing exactly what could be wrong?
If your answer is yes, these are the annoying consequences of globals. The global variables or the global states are the words every developer who has experienced working with them fears.
There are several reasons why the global state is bad in programming:
- It can lead to code that is difficult to read and understand.
- It can lead to code that is difficult to debug and test.
- It can lead to code that is not reusable.
- It can lead to code that is not portable.
Because the globals can change an application’s state unexpectedly at any time, they can make the modifications in the application difficult.
However, to save you from being in the dark while trying to modify an application, this article will cover different aspects of global states and help you understand them better.
Why is the global state bad?
Before understanding the reasons behind the evilness of the global state, you should first understand the basic concepts of a state.
What is a state?
A state is a condition in which a particular entity is at any given time. Every object in the world has a state. For example: when you turn on a switch, its state is On; when you close a door, its state is Closed.
In terms of programming, some constructs, such as variables, have a state too. When you store the values in the memory as variables, they become a state of the variable. For instance, in the following example, the state of the number variable is 5.
The state can be of any of the two sorts:
- Mutable state
- Immutable state
Mutable state:
The variables in a mutable state can change during the program’s execution at any time. They are changeable in the entire program.
Immutable state:
The constructs that are unchangeable at runtime are in an immutable state. Their value is assigned once and never changes throughout the program scope. Constants are an excellent example of an immutable state.
What is the global state?
The global state refers to the state of the variables that could be changed anywhere at any time throughout the application. The global states have the biggest scope. Using the globals, you can share the states from one part of the application to another without defining any additional functions.
Sounds incredible! Right?
Despite all the glory of globals, here is why they are bad.
Why is the global state bad?
Suppose that you are working on a huge project having global variables. Every time you want to make a slight change, you will have to
- Keep in mind that these mutable global variables exist.
- Try to guess whether they affect the scope your need to change in any way.
Besides, the global variables are shared among different parts of your application, meaning they are changeable anywhere, anytime. Any slight change in the global state can cause many problems in your application. It can make another class, method, or function behave unexpectedly due to the change. Moreover, you will have to guess the global state by looking into the entire application before making any changes to it in a particular scope.
Furthermore, suppose you use third-party libraries that use the same global variables you have defined. In that case, this will trigger the name collisions causing your application to crash and leaving you clueless regarding the issue.
Unit testing the applications having global states is another nightmare for developers as unit testing requires the units to be isolated, whereas the global states tie them together.
Simply put, the global states are bad as they make more trouble than good.
What is the local state?
A local state, local variable, or locals, whatever you call it, is a state defined within a particular scope. The local variables do not have the application scope, meaning they can only be used and changed within the defined scope.
Variables defined inside a function, method, class, loop, or any other construct are all local. You can only access them in those parts of the applications and pass them to the other parts with the help of functions.
Are read-only global variables bad or only mutable global variables?
Are the read-only global variables bad?
Yes!
Are they as bad as mutable global states?
No!
The read-only global states (also referred to as immutable global states) are common and safe to use in your application as they cannot be changed once assigned and remain the same throughout the program. While using the immutable global variables, you will not need to worry about their actual state. You will have to look to the first assignment to know their state. Besides all these positive things that immutable globals bring into your life, they are not entirely harmless!
Calling the constant global variables in different parts of your application indicates that those parts belong together. You should refactor your code to bring them together in a set of classes, a package, or whatever construct fits best. Although you can access the globals anywhere, it does not mean you should call them everywhere!
How can you prevent a global state?
Avoiding the global variables sometimes seems impossible. Managing the global variables become quite challenging in the long run. So how to refactor your code to avoid them? Here are some techniques to prevent the evil of global variables.
Function arguments
The best yet most straightforward way to avoid globals is passing the variables through function arguments. Using the globals can make your code less understandable and challenging to maintain, passing the states through function parameters can help you understand what function uses which parameter.
You can argue that what if a function requires so many parameters? In that case, you should ensure that the function is not doing more than it should. Although it seems to make your code more complex, the advantages of passing states through function arguments outweigh the disadvantages.
Another way to minimize the number of parameters is to use the Parameter object.
Dependency injection
A design pattern that implies that you should inject what your objects need directly into them at the creation time is known as dependency injection. This pattern is a great alternative to global variables.
Developers can use it to reduce the tight coupling among different components of your application. It is a wonderful technique for breaking your code into many small chunks. It also makes your code more manageable and maintainable.
The dependency injection imposes that you should not define all the functionality in a single huge service. Instead, divide the functions into lots of small and modular microservice, each having a separate duty. Furthermore, the dependency injection restricts the use of variables, objects, classes, or whatever construct you use in a limited scope saving you from lots of headaches and frustration caused by global variables.
How are globals different from a database?
To some extent, you can say that globals and databases are the same. The database can also be accessed from anywhere and changed from any part of the application connected to the database.
However, there are some differences between the globals and the database:
- Although a database is as evil as the global state, you cannot eliminate it from the system, whereas the globals are unnecessary and avoidable using some technique.
- The global variables are defined in a scope far from where you use them, and a database object is created locally wherever required.
- The global variables are shared among different parts of your applications, making the changes anatomic as all methods, threads, and objects operate on a single data piece. In contrast, when working with the database, your application operates on a copy of data, and any updates made are atomic. Furthermore, the database drivers provide a consistent and understandable interface to work with data.
That said, a database is always a better choice to work with than globals.
Is Singleton bad?
The straight answer is:
No!
The Singleton design pattern isn’t bad if used properly. The Singleton pattern implies that a class should have only one instance.
However, some programmers believe that Singleton is a bad design pattern, and you should avoid them as much as possible. In contrast, others call them useful and even indispensable in some cases.
But can it be bad in some cases? Yes!
When you abuse the Singleton pattern, it becomes bad and causes trouble. It turns bad when you use a Singleton pattern to store the global states. It is not the Singleton pattern itself but the global state that has the reputation of being bad due to the problems it causes.
How to test public static members?
The static members make the programmer’s life easier by allowing programmers to call them wherever they need them. However, the problem arises when it comes to unit testing the public static member.
You can test the public static members in the following three ways:
- Creating wrapper class and using dependency injections
- Using the static Func property
- Using the Extract and overriding call
The following article describes how to test the static methods with code examples.
Conclusion
The global state causes much trouble to the developers during the application development as they change unexpectedly. Although it seems incredible to use globals throughout the program, it becomes difficult to maintain and manage the code.
Therefore, you should avoid using the globals in your applications as much as possible to make them more robust, maintainable, and understandable.