15 ms·
Programmers are bad at managing state (2020)
- wmil 3y ago"There are only two hard things in Computer Science: cache invalidation and naming things. -- Phil Karlton" This is cache invalidation.
- hunter2_ 3y agoI always heard this with "off-by-one errors" included in that list of two.
- Ygg2 3y agoThere are only two hard things in Computer science: cache validation, off bdata races. y one,
- hnb2137 3y agoAnd only once delivery. And only once delivery.
- malfist 3y agoOnly one delivery is easy as long as you don't guarantee delivery
- paulddraper 3y ago(commenter meant to say exactly once)
- btschaegg 3y agoThis reads more and more like Monty Python's Spanish inquisition sketches. I love it :)
- Ygg2 3y agoNobody expects the Spanish Programming inquisition! Amongst our weaponry are: bad naming, undefined 46$$43$_22#3off data races. by one errors, And only once delivery. And only once delivery. And cache invalidation. And cache inva Damn it! I can't say it, you'll have to say it.
- _a_a_a_ 3y agoMethinks you need a mutex here.
- tmtvl 3y agoDon't forget naming things. I can never decide whether to call two arguments 'a' and 'b', or 'x' and 'y'.
- Ygg2 3y agoIt was consumed by undefined behavior.
- labrador 3y agoWhenever someone mentions state I think of Rich Hickey's talk "Simple Made Easy" in which he seems almost terrified of state and strives always for pure functions, because as a human he has a hard limit as to how much state he can keep in his head at once when reasoning about the program. He's right. I've worked on enough bad code, including sometimes my own, to know that programmers are bad at managing state. "Simple Made Easy" - Rich Hickey (2011) https://www.youtube.com/watch?v=SxdOUGdseq4 https://www.youtube.com/watch?v=SxdOUGdseq4
- deleted 3y ago[deleted]
- warkdarrior 3y agoThat just developers being lazy! As a user, I want my computer and my software to manage all state for me. This means remembering all data I entered (so I can continue work from where I left off), all files I saved (so I can search for them easily), all actions I've taken (so I can undo them), all sites I browsed (so I can find them again), all info I uploaded (so I can check which website knows what about me), etc.
- karmakaze 3y agoI also found this to be defeatist (and the basis of the post): > As a programmer, it’s impossible to predict all the states that your program can end up in. It's true that we can't predict all the things other programmers will change the program to do in the future, but we can take precautions such as rejecting invalid states, or if being liberal in the input it accepts transform it to something usable.
- karmakaze 3y agoPure functions are useless without inputs and outputs. The missing piece of the puzzle here is that we only want transitions between valid states. One way to define valid states is by enforcing invariants which must always be true. Armed with these, all the stuff that happens in-between can be guarded against, much like constraints in a database schema. Contrast this with non-pure functions which incrementally mutate from a valid state, to a sequence of invalid states, and end up at a valid state again. If something goes wrong along the way, we end up with an invalid state. Think about program state like it's a journaling file system.
- WanderPanda 3y ago[flagged]
- jes5199 3y agoah, statecraft
- brigadier132 3y agoI use xstate for all my ui state. I'm convinced that state machines + actors is the best way of modeling and building application state management. Going into any project and having this clear system for modeling any form of application state is extremely liberating. The problem with xstate and state machines is that the patterns are not well known yet. For example, one thing xstate encourages is creating different states for when a request is being made which is not scalable ime. Instead i think it's better to spawn a completely different actor that handles the request and then sends a message back on success or failure.
- deleted 3y ago[deleted]
- ninetyninenine 3y agoThat's why FP is such an important pattern. I'm not advocating strictly following FP but people need to learn it to understand the fundamental problem with IO and state.
- mikewarot 3y agoActually, this explains quite a lot of things that I knew, but couldn't express before. Thanks for the useful chunk to add to my map[1] of the world. It'll be interesting to see what other things fall out as I check against all the other chunks. If I could reset my browser's state with the single exception of cookies.... it would be amazing. I just don't want to have to authenticate all over again, everywhere. [1] https://wiki.c2.com/?MappersVsPackers https://wiki.c2.com/?MappersVsPackers
- 0xbadcafebee 3y agoI think this kind of misses the point. Yes, programmers are bad at managing state. But programmers aren't managing state, the programs they write are. Programmers are bad at programming. This isn't hard to understand at a fundamental level. Ask a programmer to write one simple algorithm during an interview, and there can be dozens of different bugs found. Modern software is made up of millions of these algorithms. So the potential for bugs is massive. There's simply too many things to think about, and you can't see all the invisible gotchas. We like to think of ourselves as "computer geniuses", these incredibly smart and talented humans who have an unlimited capacity. But that's just false. We're fallible in general, and software isn't an exception to that. This is made worse by the fact that there are no "building codes" for software. In physical engineering, there are all kinds of requirements to build something. You must use 10d nails for this kind of wall, spaced at 16 inches, with 2x4 studs, etc, to build a given kind of wall for a given kind of building. You're not allowed to skip them because "you don't think this needs to scale". On the other hand, adding things unnecessarily just drives up cost and makes things take longer. But we software engineers get to literally do whatever we want (and often do), with the excuse that "it's not gonna kill anybody!" But people rely on the software we write for every task in their lives today. We tell ourselves that we don't need to care how we do our jobs, which results in things like avoidable defects, and an unnecessary increase in time and money, and difficulty in just getting things done with software products. There is a simple solution to "managing state": versioned immutability. Basically, you look at something in a given state, and if it's working, you say "ok, take a snapshot of that state and give it version 1.0". Later, when the state naturally devolves into chaos, you say "ok, restore state version 1.0". This is essentially a hack to deal with the fact that we suck at making programs that can deal with entropy. But it's a hack that tends to work. In the Operations space, we've long since learned that immutability is the only simple way to make systems reliable. You can build incredibly complex configuration and state management systems to constantly try to "fix" state by poking and prodding the state back to where you'd like it to be. Or you can just... restore a backup. Kill the current thing and replace it with the old working copy. That's Immutable Infrastructure, and it's the single most powerful idea we've had for managing systems in at least 30 years. More software developers need to understand this principle and start applying it to the code they write. For example, Cloud-based services that provide no means for immutable management tend to be difficult to manage, and require complex configuration management tools like Terraform to constantly "fix" their state. The flaw isn't that the state can change - it's that the state can change into a "bad" state. We can't predict what that state will be, because again, we're bad at programming. But we can tell when the state was "good", and go back to that when things stop working. To facilitate that, a system needs to have a concept of the conditions under which it operates, and the actions taken under a given state. An example is a web app. When the web app state is "good", it can do things like process user registrations, display content, perform transactions. But when the app state is "bad", it can no longer perform the actions properly. The difference between the states is an operational state; the state which determines if the app can perform its function. Outside of that is the state of the individual actions, which will of course change during the course of the action (to perform a user registration, there must be state changes like "add a user to the database"). So software systems need to have a distinction between the kinds of state that affect operations or not, and version those, and allow easily restoring those versions.
- crq-yml 3y agoWhen state gets out of hand, I know of three options: 1. Put a constraint solver over it so that the programmer describes rulesets instead of state "paths". Regex rules like the Kleene star's backtracking are a simple example of such. 2. Put a compiler over it so that boilerplate "if" statements are generated from a smaller description. E.g. FSM compilers are one way of doing this. Years ago I read of an implementation of TCP/IP (which I can no longer find) built from a custom parser that read the actual text of the RFC spec and generated output source code. 3. Enumerate everything in an enormous decision table so that the spec is tighter.
- pdimitar 3y ago> Years ago I read of an implementation of TCP/IP (which I can no longer find) built from a custom parser that read the actual text of the RFC spec and generated output source code. OMFG! I thought of doing this a hundred times and never got around to it. Are you 100% sure you can't find it? I think such a piece of technology is extremely important!
- RangerScience 3y agoPopped in here to say that AFAIK/IMO, most of the things people treat as "state" is actually "data". And then I started thinking myself in circles around "okay, so what is state?". Rather than /keep/ thinking myself in circles, I'll ask: What do y'all think "state" is?
- azornathogron 3y agoState is data that you use in control flow decisions. (This is a 5-second reaction, not a deeply considered opinion, don't take it too seriously)
- pull_my_finger 3y ago> (This is a 5-second reaction, not a deeply considered opinion, don't take it too seriously) If you have to put a disclaimer that basically invalidates your statement, why make the statement at all?
- azornathogron 3y agoIt doesn't invalidate it, it offers context.
- gavinhoward 3y agoThis is the correct formulation. I also have a blog post coming out tomorrow with a bit of justification for this.
- RangerScience 3y agoI like it! I don't know if I agree, but, the category of "data used in control flow" is a good one. I think... maybe this definition needs a narrower category of control flow? Like, technically, if you're converting 24-hour time to 12-hour AM/PM time, you have control flow (if > 12 hours). IMO that seems like it shouldn't be state. But, "we've delivered this message, so don't try to deliver it again" definitely involves control flow and definitely feels like state. Something like "this list is sorted" is in-between; it's re-computable (easily, depending on list size), if it's not done you want to do it, but after that it doesn't affect control flow. Maybe the difference is "control flow that modifies other data"?
- rhelz 3y agoWe actually have a great tool to manage state, but nobody seems to have used it to its full potential: regular expressions. Imagine your program is a big state machine, and inputs and other events are making it transition from one state to another, and when in a state the apropos actions are performed. On this view, your program just is a regular expression parser--the tokenized stream of input events is what it is parsing. And what is a great, high-level way of describing a parsing state machine? Yup--a regular expression. When compiled, a regular expression is translated into a state machine. However, you can't really specify that an arbitrary procedure is called when it enters a state--it can only do limited actions, e.g. extract a substring. If we could let the compiled state machine call arbitrary procedures when it enters a state, well, we'd have a new program-control-flow statement. A super-duper if/then/else. Instead of writing state charts--absolutely the lowest level you can program a state machine at--we could specify the state machine in a very high-level, easier to understand and maintain way.
- mathgradthrow 3y agoWell, actually, you store your part of your state in a theoretically unbounded random access memory device, or equivalently, a tape.
- rhelz 3y agoYeah, but what if we didn't do that? I.e. when we are reading from memory, we treat it as part of the tokenized input stream, and whatever we are writing to memory is just the transformed output of the state machine. This way, the contents of the memory wouldn't be state at all; they would just be, as it were, the scratchpad where sentences in the language accepted by the state machine, or output by the state machine, are found. That's what regular expressions do for us: they are a compact way of specifying a language. Just a few characters--which is to say, just a few states--can specify a language which contains arbitrarily long strings. But--even though the input and output streams can be very large, they no longer part of the state, and thus do not contribute to the exponential blowup of states.
- kjqgqkejbfefn 3y ago
- captainbland 3y agoProgrammers are bad at managing state when they forget to use the tools made for managing state. I've had to work on code bases where the state was "implicit" and encoded in a bunch of different fields which "grew" over time and it's a full on nightmare. Even a rudimentary state machine which makes both application state and transitions between states explicit feels like a super power by comparison.
- analognoise 3y agoWhat tool do you recommend to do so?
- alwaysbeconsing 3y agoSum type is key, called "discriminated union" sometimes generally. In Rust this is an `enum`. Simulated in some languages as tuples with tag first element. Discrete number of states, attaching information only relevant to each single state. Thus, never have invalid combination of other fields.
- mrkeen 3y agoI think in this context 'state' means 'state which changes over time', not necessarily the shape of the state at rest. Turning it off and on again will fix mutable state, not poorly-typed state.
- kjqgqkejbfefn 3y agoJust look for state-machine (finite state automata) on github https://github.com/search?q=state-machine&type=repositories https://github.com/search?q=state-machine&type=repositories This is a very common pattern in Ruby to manage state. It's especially useful to guard entering impossible states with respect to business logic and figuring out what went wrong. Something along the lines of: Can't transition Command from 'ordered' to 'to-deliver': paid() == false look at this gem https://github.com/pluginaweek/state_machine https://github.com/pluginaweek/state_machine to get an idea of what features are possible
- 3y ago
- tadfisher 3y agoHiding in Jetpack Compose (Google's modern UI framework built for Android) is an incredible MVCC-based state management system that solves several problems at once: 1. Concurrent modifications: Variables wrapped in the State interface are automatically snapshotted, and readers see the most recent snapshot. 2. Observability: State reads are recorded since the last snapshot, which invalidates the Composable functions that contain the read, triggering a refresh of the UI. 3. Consistency: Because you're operating on snapshots, you don't need to wrap all mutable state in an immutable sum type; all changes are consistent with each other within a snapshot. So you can fearlessly keep state as a disconnected set of mutable variables and write naïve UI code without the boilerplate that comes with encoding state machines (or state charts). I understand that React and SwiftUI are similar to an extent, but this feels better because it's actually completely disconnected from Compose-the-UI-framework. I would love the snapshot system to be ported to other environments.