Coincidence, I've written something about it two weeks ago (in Portuguese, unfortunately: https://epxx.co/logbook/entries/sm.html). About Petri Nets as well. It is difficult to understand why so many junior programmers use a dozen boolean state variables instead of a state machine, given that they learn it in CS or similar courses. My guess is they are taught in an overly scientific fashion, so they go to the same dusty corner where so many other CS topics that are never used in practice lie already.
go to the same dusty corner where so many other CS topics that are never used in practice lie already
I've been meaning to write a letter to the CS department of one UC school: What the hell are they teaching in CS nowadays? If presented with a situation where the user can create circular references, there's one UC school that produces graduates with high 3.8+ GPAs, virtually none of whom I've interviewed can give you an implementable description of how to detect circular references. As a general pattern, they also tend to say silly things, like that a null pointer member of a structure uses up no data. I can go on and on. It seems to me they are being taught by TAs who would also flub such points in an interview.
> How is being able to detect circular references a useful skill?
For all kinds of systems, where there are references input by users as data, one needs to be able to contend with this. Systems which crawl webpages have to contend with this. Parser-transformation systems need to detect these. Such detection could be useful in memory management. It's not just the ability to detect a circular reference. It's the ability to contend with problems of that type.
Furthermore, two of those UC system CS grads had eerily similar responses, consisting of, "Oh, is that a graph algorithm?" plus a literal handwave. Is there some pool of TAs somewhere that has that attitude towards graph algorithms?
Hmm, this seems like a kind of understandable attitude if I'm reading it correctly. Hearing that it's a (standard) graph algorithm means it's a solved problem so you don't need to worry about it: pick up a text book or Google and compare the available options—easy.
It makes sense to me that junior programmers would not jump to state machines for something like, e.g., handling complex UI state. I see the reasons as twofold:
1) How would you describe the reason for using state machines over handling the state and transitions through if-statements and sprinklings of booleans? The best I can come up with is that it allows you to be explicit about which states exist, how they can be moved between, and what other code should execute when transitioning. It basically comes down to the architectural principle of 'cohesion': put related things nearby one another. This is pretty fuzzy until you've actually had concrete experience getting bitten by the lack of cohesion and attendant unmanageable complexity. To sum up, it's something you need to learn through experience—especially because another aspect of the problem is identifying situations where it really make sense rather than some simplistic heuristic about using state machines is better than not.
2) The way they're taught in school is generally about theory of automata, or they're used to diagram the behavior of some simple little system. Using them to control state transitions in applications is unlikely taught at all, and isn't really directly implied by the seemingly related things which are taught.
> It is difficult to understand why so many junior programmers use a dozen boolean state variables instead of a state machine
It's not just juniors. The only times I've encountered state machines in the wild are almost exclusively games and virtual machines/interpreters.
The reason, to me at least, is pretty clear. In both games and VMs, you mostly know the rules ahead of time. You have a clear picture of the opcodes you want to implement (add, mul, call, jump, etc.) or the game rules you need.
But for most development, especially with multiple stakeholders or customers and multiple developers working independently, the rules aren't known at the start. In fact, the majority of requirements are brought up months or years after the first line of code is even written. It's like the parable of the blind men and the elephant (https://en.wikipedia.org/wiki/Blind_men_and_an_elephant). Each person, working separately, has a different idea of what this thing is that you're creating. Communication being an incredibly difficult thing, the requirements are never fully rendered coherent by the entire team at the moment where it would benefit them most (i.e. the beginning).
In my experience, this is when you need the skill to know to refactor to a state machine and/or refactor to some other form of composition (strategy objects, has-a, or whatever).
As taught in school, State Machines are formalisms that fit well when everything can be formally specified. As I have learnt, State Machines in programming help to reorganize things that have evolved haphazardly.
> O autômato mais poderoso é a Máquina de Turing, a que equivale todo computador de uso geral.
It's the most powerful realizable automaton (although it's not even fully physically realizable because of the infinite tape), but people have studied far more powerful automata:
In these models the oracle is so called by analogy to prophetic oracles of antiquity, who were believed to obtain reliable information from an incomprehensible and supernatural source. :-)
> It is difficult to understand why so many junior programmers use a dozen boolean state variables instead of a state machine, given that they learn it in CS or similar courses.
If you think that's a head-scratcher, the fact that senior developers consistently do the exact same thing must really confuse you!