0 added
0 removed
Original
2026-01-01
Modified
2026-02-21
1
<p>You can write any code inside files (and outside of definitions) in scripting languages like JavaScript. This can be defining and calling functions, or declaring and changing variables. This freedom simplifies development by allowing you to create one-time scripts for simple or infrequent tasks. On the other hand, careless development leads to flaws that make the code and maintaining it significantly more difficult. They're so common in production code that we need to address them separately.</p>
1
<p>You can write any code inside files (and outside of definitions) in scripting languages like JavaScript. This can be defining and calling functions, or declaring and changing variables. This freedom simplifies development by allowing you to create one-time scripts for simple or infrequent tasks. On the other hand, careless development leads to flaws that make the code and maintaining it significantly more difficult. They're so common in production code that we need to address them separately.</p>
2
<p><em>These problems are not unique to JavaScript; they occur in many other interpreted languages, including Python, Ruby, and PHP.</em></p>
2
<p><em>These problems are not unique to JavaScript; they occur in many other interpreted languages, including Python, Ruby, and PHP.</em></p>
3
<p>You can read more on the difference between modules and scripts in our<a>article</a>. Here we’ll focus on flawed module design.</p>
3
<p>You can read more on the difference between modules and scripts in our<a>article</a>. Here we’ll focus on flawed module design.</p>
4
<p>Assume we have an<em>index.js</em>module with the following content:</p>
4
<p>Assume we have an<em>index.js</em>module with the following content:</p>
5
<p>Some other part of the program imports and uses it. The import of these modules typically takes place in various places across the program rather than in a single one.</p>
5
<p>Some other part of the program imports and uses it. The import of these modules typically takes place in various places across the program rather than in a single one.</p>
6
<p>The question is, how many times the contents of the<em>index.js</em>file are actually called? It is easy to check by printing something inside a module:</p>
6
<p>The question is, how many times the contents of the<em>index.js</em>file are actually called? It is easy to check by printing something inside a module:</p>
7
<p>By running the program, you can see that the call occurred just once; the same with the constant. In this respect, export is very different from return inside functions. return is invoked on every call, and export is called only on the first import, and then it’s just reused.</p>
7
<p>By running the program, you can see that the call occurred just once; the same with the constant. In this respect, export is very different from return inside functions. return is invoked on every call, and export is called only on the first import, and then it’s just reused.</p>
8
<p>This feature has a remarkable implication: the module can easily be turned into global state storage.</p>
8
<p>This feature has a remarkable implication: the module can easily be turned into global state storage.</p>
9
<p>Somewhere in other parts of the system:</p>
9
<p>Somewhere in other parts of the system:</p>
10
<p>Even though these are separate files, the object imported from<em>state.js</em>is always the same.</p>
10
<p>Even though these are separate files, the object imported from<em>state.js</em>is always the same.</p>
11
<p>What exactly happened here? Even though the code seems convenient to use, it’s based on practices that have always been considered bad. In fact, it creates a global variable that can be accessed and changed by any part of the system (via import). This is extremely dangerous and can result in serious errors, so global variables should be avoided whenever possible.</p>
11
<p>What exactly happened here? Even though the code seems convenient to use, it’s based on practices that have always been considered bad. In fact, it creates a global variable that can be accessed and changed by any part of the system (via import). This is extremely dangerous and can result in serious errors, so global variables should be avoided whenever possible.</p>
12
<p>Access methods that are added to the state can aid in solving the issue in part:</p>
12
<p>Access methods that are added to the state can aid in solving the issue in part:</p>
13
<p>Thus, we will get not just global data but a global object (in the OOP sense, not a data type). This, however, makes little difference. Global data remains global.</p>
13
<p>Thus, we will get not just global data but a global object (in the OOP sense, not a data type). This, however, makes little difference. Global data remains global.</p>
14
<p>Why is it so bad? Assume we've created an autocomplete library and connected it to the page. This library most likely stores data from the backend, for example, to speed up access. Then we have a task to connect two autocompletes on the same page, and this is where the surprises will begin. Changes made to one autocomplete will affect the other.</p>
14
<p>Why is it so bad? Assume we've created an autocomplete library and connected it to the page. This library most likely stores data from the backend, for example, to speed up access. Then we have a task to connect two autocompletes on the same page, and this is where the surprises will begin. Changes made to one autocomplete will affect the other.</p>
15
<p><em>Theoretically, various autocompletes could use different data sources. However, the issue will persist when dynamically adding and removing autocompletes, for example. Thus, there is no way to design such an implementation that is error-free in any circumstance.</em></p>
15
<p><em>Theoretically, various autocompletes could use different data sources. However, the issue will persist when dynamically adding and removing autocompletes, for example. Thus, there is no way to design such an implementation that is error-free in any circumstance.</em></p>
16
<p>Here is another example. In tests, such mistakes immediately get to the surface. Tests should not be interdependent and entangled, which is impossible with a global state. Any changes to the state in one test will be mirrored in the other. Manually restoring them to their previous state is possible, but it is incredibly unreliable (it takes mastery to handle errors). It also adds a lot of unnecessary complexity.</p>
16
<p>Here is another example. In tests, such mistakes immediately get to the surface. Tests should not be interdependent and entangled, which is impossible with a global state. Any changes to the state in one test will be mirrored in the other. Manually restoring them to their previous state is possible, but it is incredibly unreliable (it takes mastery to handle errors). It also adds a lot of unnecessary complexity.</p>
17
<h2>Contents</h2>
17
<h2>Contents</h2>
18
<ul><li><a>Local state</a></li>
18
<ul><li><a>Local state</a></li>
19
<li><a>Valid global state</a></li>
19
<li><a>Valid global state</a></li>
20
</ul><h2>Local state</h2>
20
</ul><h2>Local state</h2>
21
<p>Localizing the state within the application is the correct way to work with it. In the case of autocomplete, for example, it could be a function:</p>
21
<p>Localizing the state within the application is the correct way to work with it. In the case of autocomplete, for example, it could be a function:</p>
22
<p>And usage:</p>
22
<p>And usage:</p>
23
<p>Сode is structured in such a way to enable adding as many autocomplete as you want without worrying about them interfering with each other. Each autocomplete has its own local state to work with.</p>
23
<p>Сode is structured in such a way to enable adding as many autocomplete as you want without worrying about them interfering with each other. Each autocomplete has its own local state to work with.</p>
24
<p>The same should be done in all other cases, whether we use frameworks or native JavaScript. The general principle of working with the state remains the same - the entire application is wrapped in a function that determines the global state for a specific application but is local to the application's run environment.</p>
24
<p>The same should be done in all other cases, whether we use frameworks or native JavaScript. The general principle of working with the state remains the same - the entire application is wrapped in a function that determines the global state for a specific application but is local to the application's run environment.</p>
25
<h2>Valid global state</h2>
25
<h2>Valid global state</h2>
26
<p>Are there any cases of a valid global state? At the very least, many libraries use it for configuration or internal needs. As previously stated, this can cause some problems, but it is not always significant:</p>
26
<p>Are there any cases of a valid global state? At the very least, many libraries use it for configuration or internal needs. As previously stated, this can cause some problems, but it is not always significant:</p>
27
<p>Overall, never save data in a global state; only use objects that were created within the application.</p>
27
<p>Overall, never save data in a global state; only use objects that were created within the application.</p>