
Global Mutable State - bhalp1
https://dev.to/ericnormand/global-mutable-state
======
SCdF
One of the most confusing things I find with web development (which I'm mostly
new to, coming from a backend background) is that everyone seems entirely
happy with JS (or more accurately the DOM?) and CSS being giant mutable state
buckets.

I've worked in mostly backend software for a decade, and web dev is easily the
hardest thing I've ever had to work on.

CSS especially is a nightmare. It's near impossible in complex projects to
work out if your change is going to change other things adversely. Not only do
you have to know all usages of the CSS class (for example), but if it's a
scoped class (.foo .bar) you have to know all instances in which is it scoped
in this exact way. Because it's visual you're basically testing with your
eyes, there is no "refactor to green" possible.

In Javascript it seems normal to (at least in angular) push to global scope,
and so it can be really unclear where values come from, or how they get set.

I once tried to work out why a fancy ajaxed select box (rendered in JS / CSS,
naturally) was firing its onblur event at the wrong time. There were _at
least_ three JS event handlers (from memory, jquery, angular and native) that
could possibly have events against it. Everything is smushed together, and
because it's about losing or gaining focus the observer effect comes into
play, and… it's a nightmare. From memory I just gave up, and I presume that
particular bug still exists today.

Testing any of this stuff is also pretty nightmarish. Knowing the web I'm
almost certainly behind the curve and there is new hotness out to solve this,
but I've never much luck with automated browser testing. Things like
Protractor tests are incredibly onerous to write, and inevitably end up as
flakey slow messes that fail builds due to flake more often than they find
issues.

I imagine there are lots of ways to solve these sorts of things, but all I've
read feel like variants and retellings of "do it right", which isn't really
that helpful, because a) what is right?, and b) it's easy to slowly slip away
from "right" without noticing.

~~~
ams6110
Yes it's really quite amazing that browser development has gained the traction
it has, considering what a terrible environment it is to work in. I think its
a combination of a lot of devs never having done anything else, so they don't
know better, and also that removing the friction of deploying and configuring
native apps was worth all of that.

~~~
rmrfrmrf
* lowest barrier to entry of any platform

* View Source of anything

* development tools that keep improving by the day

* non-proprietary, open standards

* completely sandboxed from host environment

* runs anywhere

* first-class GUI support

The list goes on...

~~~
otakucode
Right... when was the last time you USED View Source on something done in JS
and actually used on a production site? Sandboxing from the environment also
has its upsides and its downsides. What people actually want applications to
DO is deal with their information. And sandboxing the host means they lose any
semblance of control over that data, leading to it getting monitored, mined,
etc. And it doesn't solve any of the actual problems. It just changes the
target while simultaneously making those targets SO much juicier. Want the
personal info of 143 million Americans? Hack the web app of a credit company,
no need to hunt down and break into 143 million different machines! And the
users won't even know if the data was stolen unless a company volunteers the
information! Sometimes they even do!

I really, really have to wonder about "first-class GUI support". Prior to the
web applications used standard UI controls. Because that makes sense and makes
computers easy to use. The web brought 'every single UI is different', which
is horrendous. And when you can manage to put together a UI with web tech,
then it's trapped in the browser. Which actively goes out of its way to make
it as difficult as possible to manage running several different things at
once.

I think the answer to the webs success boils down to delivering what users
actually want. Despite all the other warts, its valuable enough to convince
them to not care. They want to search for something they want, vaguely, and be
using an application one second later. All other considerations be damned.
They'll wrestle with confusing UIs that change all the time without warning.
They'll accept not having a lick of control over their data. They'll deal with
being aggressively advertised to and companies trying to hound them into
subscriptions because the 'service' of working around the sandboxing by
keeping their data together needs ongoing cash infusions when the user only
wanted a single product they could use for long periods of time. Like if
people who made hammers started making ones that would only work with nails
gotten from the hammer manufacturer and they didn't permit you to get enough
to last, requiring a subscription so they could sell the information about
what kind of nails and how often you were using them to a nail company.

~~~
celim307
> when was the last time you USED View Source on something done in JS and
> actually used on a production site

I don't disagree with most of your post but I am confused why you brought this
up as a point of contention. Viewing source is pretty common?

~~~
tene
My understanding of this argument, as best as I'm able to state it, is
approximately: Claims that view-source is a significant virtue of the web are
nostalgic and misguided, as demonstrated by the fact that it's difficult and
rare today to find anything usable or valuable by reading the javascript
source of major websites like facebook, especially by amateurs.

It's possible that I've misunderstood some nuances about the claim, and I
apologize if I've misrepresented the comment you're replying to.

~~~
jonnyscholes
Sure large sites with extraordinarily valuable IP make it hard to view source
and learn anything. However other smaller sites are a wealth of wisdom. Just
the other day for example I inspected the new KIKK website to see how they
managed to keep their website silky smooth on mobile whilst cramming quite a
few transitions/animations in.

And for that matter I learned a heap inspecting (whilst attempting to reverse)
Google's culture project. Specifically how they protected their image assets
using a novel technique (since this was in pre-web-DRM world).

The other thing is as sites know their code is in the open I suspect it's
easier for devs to get internal approval to do write ups of particular
techniques.

------
sago
I'm a bit sceptical about the ragging on global mutable state, given how
useful it is (in my use cases, for resource management, e.g. connection
pooling, caching, JIT compiling, file loading).

Global mutable state is akin to an external interface. The user is a global
mutable state. If there is no user, then the external data the program is
interacting with is often global mutable state (it may change in arbitrary
ways, and your program should behave differently), a database is global
mutable state, as is the DOM / UI.

So, beyond the 101-level advice (don't use global variables, prefer explicit
state, reduce visibility, etc.), global mutable state is unavoidable, and it
needs to be treated as 'external' by any code that uses it. I think that is
the problem. Not so much global mutable state, but global mutable state with
privileges, global mutable state that any bit of code makes assumptions about.

Program defensively against global mutable state. Reduce it, but don't be
religious about it. It's still a tool in the toolbox if needed.

~~~
kibwen
I agree that going to the extreme of 100% eliminating global mutable state is
going to fail for practical purposes, but we don't need to go that far to
benefit.

I think of the code that I wrote when I first started programming. Nearly
every variable was global, because I simply couldn't be bothered to think
about where it could be accessed from. But nowadays I can't remember the last
time that I used a global variable, and I'm no worse off for it. For beginners
it's a tempting tool to turn to, and we need to continue teaching aversion to
it. Like `goto`, we can both consider it harmful and also happily allow its
use when well-considered.

(Historical fact: very ancient versions of Rust didn't have global state at
all, as Graydon was hoping to find a way to avoid ever needing to use it;
eventually he was persuaded otherwise. Though global mutable state in Rust
still requires the `unsafe` keyword to access due to the risk of concurrent
access, so it's rare to see it in the wild (and quite obvious when it is).)

~~~
sago
I agree.

But here's the problem I have. If we don't want people to use global
variables, the advice should be 'don't use global _variables_ '. There is no
need to wrap it up in 'avoid global mutable state', when using global mutable
state is unavoidable in many cases and the best engineering solution in many
others.

At the point you have to nuance it to 'reduce your code's exposure use global
mutable state, accessing it through mockable interfaces, and defensively
checking its values' to mean 'don't use global variables', it may be simpler
to say what we mean.

For example: there is a comment lower down in this thread of someone confused
by the advice in the context of the game engine. I've worked with hundreds of
game engines, every one of them has global mutable state.

~~~
otakucode
In many languages, variables are not necessarily state. Global variables are
fine if they're global constants which can not (not just 'should not') be
modified.

------
shalabhc
Isn't a database global mutable state? Or a filesystem?

If global, mutable state is considered problematic when programming in the
small (i.e. single program), why is it unquestioned when building much larger,
more complicated systems that we also need to reason about?

~~~
inglor
A database is only global and mutable if any part of your code can create it.
If you isolate the database access to one module and then force other modules
to interact with it through instances of that module in a controlled way -
it's not global (but certainly mutable).

The same goes to your filesystem, the key thing is: global as global access
vs. global as "there is one of it". The same goes for the singleton pattern
(which are terrible) vs. just having one of something.

~~~
adrianratnapala
I don't get this.

Once you mutate the database, then the behaviour of any code anywhere that
uses the DB, whether directly or through a module is potentially affected by
the mutation.

Modularisation is great and all, but it doesn't make concurrency and cache-
coherency problems go away. In fact it sometimes makes those things worse (or
at least more opaque).

~~~
wiz21c
The database (at least the relational ones (I don't know the nosql thing)) is
actually a very well behaved global state. It gives you guarantees about its
mutability which you often don't have in your own code (well, in mine at least
:-)). Moreover, the transactional nature of those DB actually percolates in
many places in the code and makes it more reliable. So I'd say the database is
a very special mutable thing, it's not as general as the usual proposal of GMS
and therefore, it's much less dangerous.

------
roywiggins
The absolute worst type of global mutable state I've had to deal with
personally follows this antipattern:

    
    
        oldEnvironment = getGlobalEnvironment()
        SwitchToGlobalEnvironment("Foo")
            - Do things that rely on the "foo" globals
        SwitchToGlobalEnvironment(oldEnvironment)
    

Or, worse, functions like this:

    
    
        // NOTE: DO_STUFF assumes "FOO environment". Set FOO ENVIRONMENT before you call it.
        def doStuff() {
           - Do stuff that relies on foo environment
        }

or:

    
    
        // NOTE: depends on the value of global FooBar. Adjust FooBar to make DoStuff2 behave how you want
        def doStuff2() { ... }

~~~
ams6110
I suppose you never worked with old ASP or PHP apps where the first thing
every page did was throw every form field value into the global Session
object?

------
ajuc
IMHO the main problem with mutable global state is - you don't know what
caused it to have the value it has.

The solution is traditionally access restriction (OO) or immutability (FP),
but it can also be - strict no aliasing rule.

Imagine if there were only 2 kinds of functions: pure functions (that can
accept parameters have local cariables, and return values, but cannot change
nor reference global state), and impure procedures (that cannot accept
parameters and doesn't return anything, but can reference and modify global
state, always starting from root object and going through all nested objects).

Then if you want to know ALL plaes which could have influenced or depended on
the value root.objects.player.x - you simply search for that exact string.

You can start with all code using global state directly, and slowly move parts
into pure functions. It can even be automated.

------
yathern
I'm working on a toy game engine for fun. What about the pattern of having a
globally accessible list of game entities? EG when a bullet hits an object do
(psuedocode)

    
    
      Game.getEntityById('player').applyDamage(20);
    

The bullet class then has access to all entities in the game and can mutate
them. Global Mutable State, no? Barring the performance issues of doing this
lookup dynamically, is that so bad?

~~~
benaiah
You can have that kind of flat, global structure without _mutability_. One way
to do that would be to collect all actions done in each frame (instead of
mutating) and then apply them all to create a new frame in a single step (a
"reduce"). Then you call the game loop function with that frame to create
another frame, etc. The issue isn't just _global_ state, it's global _and
mutable_ state. Say that your game has a debuff that reduces the damage of an
enemy, and your player debuffs an enemy in the same frame that it attacks him.
If you're mutating everything, it can be very difficult to figure out or
specify what order things like that happen in, since anything can mutate
anything else at any time (concurrency makes this _much_ worse). If you're
using mutable state, there's no way to tell all the places that could be
changing the enemy's damage, because it could be _anywhere in the program_. If
you're passing everything through as arguments, it's very easy to see exactly
where state changes occur and make code modifications in isolation without
worrying about affecting unrelated behavior.

~~~
yathern
That's an interesting concept - I'm not sure I'm fully understanding though.

In your example - in the 'reduce' step - the implication is that the attack
and debuff are handled in a deterministic way, regardless of their order? I
feel like then that would require the logic for reducing all game commands
needs to reside in the engine loop, which doesn't seem right to me.

~~~
Veelox
Background. There are two ways gamers think about games "real-time" and turn-
based. The question about a bullet is most likely referring to what gamers
would call a "real-time" game. The thing is, we programmers are forced to make
the game happen in discreet steps. There are multiple ways to accomplish this.

The naive way is to give every object in your game an Update() then on each
discreet step you iterate through the list of objects in your game and call
Update(). This way lies madness because every object can interact with every
other object from any Update() and you can never know where the changes are
coming from.

The concept above is that you move up a layer of abstraction and you create a
GameState object that contains all objects. You instead give each object a
GenerateUpdates() method that returns a list of GameStateChanges. Thus to
update the game, you take the GameState, iterate through each of the objects
in GameState and get a list of GameStateChanges. You then pass both to either
GenerateNewGameState (if game states are cheap) or ApplyChangesToGameState (if
they are expensive). This reduces all of your mutations to one method and is
much easier to update/debug/fix/understand.

Does that help?

------
deckarep
Try dealing with global mutable state in a multi-threaded scenario. This is
when the real fun begins...

~~~
jon_adler
We are investigating using Scala and Akka (using actors) for concurrent
processing. No locks are needed...

~~~
kaeluka
Unless two actors share state, or use global mutable state.

------
asow92
You can't build products without mutable state. How far should we go when we
reason about global mutable state? Do we go as far as the database layer?
Computers are state machines and I don't know why we're so eager to get away
from that. Separation of concerns and interfaces/protocols help, but somewhere
down the line, it's accessible, mutable, and it's stateful.

------
JadeNB
> When people say "it's hard to reason about", what they really mean is "it's
> got bugs and you can't tell by reading the code".

This obviously isn't true universally, and almost assuredly isn't meant to be;
but, even interpreting it in the spirit in which it seems to be meant, surely
the right translation is "you can't find bugs in a given code unit by reading
only that code unit" or, more positively (?), "to find bugs in just one code
unit, you have to read all the code."

~~~
scarmig
Maybe for a sufficiently smart person, you can find all the bugs by reading
all the code. But if you've got a concurrent program that modifies global
state haphazardly, a sufficiently smart person doesn't exist.

~~~
clusmore
>There are two ways of constructing a software design: One way is to make it
so simple that there are obviously no deficiencies, and the other way is to
make it so complicated that there are no obvious deficiencies. The first
method is far more difficult. -Tony Hoare

------
slavik81
Global mutable state is just the worst-case of a more general problem.
Unnecessary scope and mutability make programs harder to reason about because
when trying to understand code they require you to investigate things that you
might otherwise be able to instantly rule out as impossible.

------
throwaway613834
Very relevant (and, I think, excellent) article:
[http://misko.hevery.com/2008/08/17/singletons-are-
pathologic...](http://misko.hevery.com/2008/08/17/singletons-are-pathological-
liars/)

------
kahlonel
A great way to get rid of global data (mutable or not) is to write testable
code, and then write unit tests. I'm not a big fan of TDD or unit testing, but
it does force you to think in terms of "contexts".

------
xamuel
It's funny how closures are in-fashion and global mutable state is out-of-
fashion, when the latter is really a special case of the former.

~~~
SCdF
How are they related sorry?

I know in ES6 closures inherit the scope they are declared in, but I don't
think that's a required part of the concept is it?

~~~
xamuel
Consider this ES6 program: (function(){let x=0; let f=()=>{x=1}; f();
console.log(x);})()

Is x a "global mutable state" variable? If the above is the entirety of the
program, then essentially yes. If you say "no, x is not global mutable state",
then "global mutable state" is pretty meaningless in JS, since any script can
be wrapped like above.

