Undo/redo seems like one of those problems where the knowledge of how to actually do it properly seems lost. People just dig up the supposedly 'solved' ancient solution and then cargo cult it.<p>So you end up with something like this, which looks like a polished and approachable library of a "standard" command pattern. But if you use patterns modeled after single user / local-only apps, you will code yourself into a corner.<p>i.e. In a multiplayer environment, the command pattern is not what you want, because every user has to be able to undo only their own local changes. This means rebasing the local undo/redo history on top of remote changes. Reverting an operation might not result in the same state you had when you performed the action. If the logic of how the command works is frozen inside the code inside a class, no other code can operate on it.<p>I've had much more success with a more functional method based on diffs and patches, i.e. mutations as data. For convenience as a dev, you want to be able to express local changes in a non-reversible way, without the undo/redo nature of the app forcing you to rewrite every change as a non-composable command.<p>You can then convert these into reversible changes automatically (e.g. OTs), which you can put in your undo/redo history, and which can be rebased over each other.<p>I've been trying to lone-star adding proper undo/redo systems to the apps I work on for years, and it always runs headfirst into the fact that the other devs—especially back-end devs—are not able or willing to admit that most everything they know about building applications is wrong and has to be thrown out.<p>These people of course also swear by Git and would refuse to do their jobs without it.