Hacker News new | past | comments | ask | show | jobs | submit login
Undo (sachagreif.com)
300 points by sgdesign on Nov 20, 2013 | hide | past | favorite | 98 comments

You use Gmail's undo feature as an example, but it doesn't work in the way you prescribe. It's the cheap & easy version of undo that doesn't require building your application around the command pattern: just implement a reasonable delay before making the irreversible change, and show the Undo action during this delay (which is really a "cancel the pending change" action).

No, it's not as clean or as good of an experience for your users, but it works great for applications such as email that perform fundamentally irreversible actions.

Yeah, it's kind of a simulated undo. I'll update the post to point it out better. But anyway, the end result is (almost) the same for the user, which is what counts at the end of the day.

There are actual undo in Gmail as well, for example when applying a label to a message.

Since send is making the change in an external system it has to be simulated, but that doesn't change the point of the post.

"Undo" only makes good sense in an app where each user works in her own isolated sandbox. This is a common paradigm on the desktop (e.g. word processing), but less common on the web. As soon as Alice's transaction is visible to Bob, making it undo-able gets much more complex.

This is a good point, but as the author points it, it feels so useful in Gmail.

Gmail undo is basically job cancellation, not really returning a changed state back to its original state.

Gmail can't "undo" once that job has been processed - in other words, when something has been actually done.

We, on HN, all have an idea of the tech behind this, but to the user, it is still perceived as an undo action, and that's what I believe the point of the author was.

It's not job cancellation, your view is such that unless you undo, that's reality (you can confirm this by browsing in a separate window, your non-undone actions have taken place).

What Google is doing is (at least for deletes on mails) is equivalent to a database transaction rollback. So they have a tiny (likely 1-entry) transaction log that they keep per user, and if the user desires, they can use it to fully reverse any operation that is undoable aka reversible.

I suppose it works different for email sends you can undo - in that case it is job cancellation.

Gmail can't, but Exchange and Skype can (and do).

How does Google Drive handle this?

Doesn't Drive, just like Dropbox, simply version everything similar to a source control system?

Using the optimistic locking pattern, this would mean that Alice could undo, and if Bob then makes changes referring to Alice's entry, it'd be pointing to a previous versioned entry (Alice's undo would simply copy version n-2 and make it version n while Bob would be pointing or editing version n-1)

Not sure. That behaviour would be a little weird, if Alice hitting Ctrl-Z undoes what Bob just did. Google Drive's document editors explicitly appear to support "undo".

Implementing a passable undo with a database-backed system gets a lot easier if you have an append-only record of every transaction.

Rails has a great gem that adds this feature with a minimum of fuss (https://github.com/airblade/paper_trail). There's even a Railscast that goes over how to use it to implement "undo" (http://railscasts.com/episodes/255-undo-with-paper-trail).

I would wager that the reason Undo isn't implemented more often is that it is very difficult.

Executing a DELETE statement and deleting a bunch of data is simple. Implementing "undo" is more difficult, especially for browser based software. How long is the undo valid for? Can you undo every action? How many levels of undo do you support? Do you allow an undo for UPDATE's as well (updating a blog post to set it's content is essentially deleting it, and would probably be something you want undone, for example).

On top of just building the functionality in to your app, communicating it to your users is also difficult since the web app medium is so different than the desktop one.

Instead of actually deleting a record when a user hits 'delete' just flip a boolean that indicates it is 'deleted'. Then undoing a delete action is as easy as flipping the boolean back. For more complex application state you can keep a stack of state or actions (depending on the application and code) and then push onto the stack as the user performs actions (killing off actions older than a certain point). When the user hits undo pop from the history stack and push onto a second 'future' stack to support redo. I agree with the author that it would be nice if more web apps implemented undo/redo. I Iecently implemented it in an interior design app I was working on and it's really not that hard to do.

In a traditional 'desktop style' app simply ported to the web this may be possible. But in a multi-user app that may not be the case.

What if the record you deleted was subject to some kind of uniqueness constraint. If another user has added a record that has the same data, then flipping the delete flag off again would not violate that constraint.

Sure, it could be handled by checking if the constraint is violated. but you rapidly run into a lot of code to implement that one feature and dealing with thinking of and testing all the edge conditions makes it much easier (& cheaper) to focus on other features.

I just went through it, it is actually difficult, but not THAT difficult. You don't flip a flag, you implement a Command pattern of sorts: instead of deleting an object you record the command "DELETE" along with the copy of the object. When you want to undo delete, you take this record, change "DELETE" to "CREATE" and submit this command to execution. Then all the constraint logic works as if you're creating the object from scratch, with possible conflict resolution along the way. Undo is easier if it's not an implementation of time travel but redoing something you did previously in the opposite direction.

I think those constraints are often the same as when you create a new record, so you can reuse code from there. But I'm sure there can be edge cases that make it tricky for some apps and/or situations.

Undo and redo aren't important features for every web app - in some they would't make sense at all - but for applications that facilitate any kind of creative process, such as photo editing, 3d modeling, or drawing, they are very important features to include. Users often want to try out an idea, then go back to an earlier version if the idea doesn't work out. In most cases for apps like these implementing undo/redo gives you a ton of usability bang for your proverbial buck.

That may or may not be legal. IANAL but telling a user that his/her data has been deleted when in fact it still sits on the server could be regulation violating or downright illegal depending on where you are. Of course it would probably also depend on what your product ToS says and the nature of the data being deleted.

> IANAL but telling a user that his/her data has been deleted when in fact it still sits on the server could be regulation violating or downright illegal depending on where you are

Where on Earth do you think labeling a button "Delete" is a legally binding specification with an incredibly specific required implementation?!

EU member states are subject to the (soon to be rewritten) Data Protection Directive: http://en.wikipedia.org/wiki/Directive_95/46/EC_on_the_prote...

In the UK, for example, this is implemented by the Data Protection Act 1998: http://en.wikipedia.org/wiki/Data_Protection_Act_1998

The guidelines for complying with the DPA talk a bit about deletion here: http://www.ico.org.uk/for_organisations/data_protection/the_...

"If you offer users the option to delete personally identifiable information uploaded by them, the deletion must be real i.e. the content should not be recoverable in any way, for example, by accessing a URL from that site."

In fact the DPA takes it even further by requiring that personal data "shall not be kept for longer than is necessary" ie. you are supposed to delete any personally identifying data once you're done using it for it's original purpose (or another legal use). Granted, I imagine it would be pretty hard to bring a case against a company for either of these things, and I can't tell if the former is legally binding or just a "guideline," but it's not outside the realm of possibility...

> the DPA takes it even further by requiring that personal data "shall not be kept for longer than is necessary" ie. you are supposed to delete any personally identifying data once you're done using it for it's original purpose (or another legal use)

I think you could easily argue that "needing it for an undo feature" is still a legal use for that data. But, thanks for pointing out that "delete" is a lot more legally loaded a term than I had assumed. It makes a pretty convincing case to call things "remove" instead of "delete".

Maybe so, I'd be really curious to talk to a UK lawyer who has some experience in these matters to get a sense for how they're enforced. Thanks for asking the question and inspiring me to do the research - like you I assumed there was no way "delete" was regulated, but decided to look it up before replying and was very surprised.

Probably a place on Earth that legally frowns upon deceptive business practices, false advertising, and the like.

> Where on Earth do you think labeling a button "Delete" is a legally binding specification with an incredibly specific required implementation?!

It may not be "legally binding", but it certainly is a big risk: look at all the hoo-ha when (e.g.) Facebook/Adobe/etc. don't really delete your profile.

Note that I'm not saying they should/shouldn't: I'm arguing that there's many cases where indicating something is deleted (and not deleting it) can cause user outrage.

> I'm arguing that there's many cases where indicating something is deleted (and not deleting it) can cause user outrage.

Oh, definitely; that's a great way to piss people off. But jd007 specifically mentioned that it might be "downright illegal", and that's what I was criticizing.

I'm not sure about the legal implications either, but it would be interesting to know. From a totally different angle it might cause backlash from users if they felt betrayed by an action not actually doing what they thought it would do. You'd have to balance the conflicting desires to be able to undo things and have actions do what they say they will do. Maybe a 'trash can' or 'archive' system is the way to go.

Isn't that exactly what Facebook and every other social network does though?

Yes, and they keep getting flack from various regulatory authorities for things like that. Facebook or anyone doing something that isn't legal doesn't make it legal.

They don't even do a good job of hiding it :/ the URL of the image stays the same and it is still accessible through the URL. All they do is remove its link from their interfaces...

The problem with adding tombstones to a schema is that they infect every join and you must manually cascade the delete in related tables. For simple schemas, like a blog or simple cms it is manageable but it gets hairy as your schemas get more complex.

This is 100% accurate. In some cases you can't use a unique on a column because of the "deleted" boolean or a state machine that is in a deleted state. I would venture to guess that this is where a NoSQL solution would come in handy. Just grab all the data they deleted, shove it into a nice json or xml data structure and store it in the nosql database as a document.

An undo feature for updating a blog post would probably be better described as a roll-back. Wordpress implements this buy saving each revision as a new row, with the most recent indicated by a flag.

You definitely can't undo sending an email notification so additional emails will have to be sent when an action is undone, which in the end will create more problems, annoy or confuse users.

MS Outlook has taken this approach, IIRC - you can send a "message cancellation", which is actually just an e-mail with a special header. This, however, requires all the people in the conversation to cooperate, i.e. use Outlook.

Hilarity ensues when someone tries to pretend that a message never existed by cancelling an e-mail sent outside Outlook's garden. (The non-Outlook user will get both the original and the "previous message doesn't exist, okay? Wink wink, nudge nudge" message.)

I felt like I was having déja vu reading this article. Happy to have found why, Aza Raskin in 2007: http://alistapart.com/article/neveruseawarning

You're right, very similar point. I'll add a link to it, thanks!

Me too! Many thanks for finding and linking it. (Not complaining. Both are good)

Interesting write up. Thanks a lot for writing it Sacha.

Okay, so I have a question. Isn't this just a property of the internet as a system?

If we remember the history of human-computer interaction on 2D displays, we first really remember what led to the desktop GUI (Xerox Alto, all that stuff). This domain had tons of research poured into it (of which Raskin is a member) - including from the military, for usability in extreme situations - and by now it's reached a pretty mature stage, and we have developed a nice design language to describe it and advanced technological tools to implement that language. On my Finder, or in Pages, I can reliably undo things nicely. Just today, I deleted a file by mistake- command + z, boom, undone.

(by the way, this is exactly what Apple and mobile devs talks about when they say that well done native apps can never be beat by web apps- those decades of best practice experimental research)

Web apps, on the other hand, run on the internet, which adds some constraints structure wise. All of a sudden, we have at least 2 computers talking to one another, and in most cases many, many more than that. So we have to come up with design principles to make all of this somewhat work together, and we come up with things like RPC and REST. Those things are how our servers talk now, and they influence every technology that we build. They come with some constraints however- notably the ideal of statelessness, in which implementing "undo" would be really hard. Relational databases don't have the semantics to express "undo the last statement that was a user action done with id N", and good luck implementing things like undo in a system where you have caches you can't invalidate, content determined by one way hash functions, etc. If you have a binary blob of 5 lines, that user 1's action modify the first 3 lines, that user's 2 action modifies the last 3, and that user 1 then decides to undo his command?

You'd basically have to version everything, and have super amazing algorithms doing bisects and diffs on your content.

The http internet is really just a way to exchange documents. We've hacked it, using fancy stuff like AJAX, to make it behave more like the traditional GUI that we know and love, but at the core it's still a way to transfer documents. And naturally, HTML, the description language we use for web content, has semantics for describing static documents. Heck we've had to design a whole new language for design (CSS), because it's really just a way to describe documents! So ultimately it lacks the way to implement concepts like undo-ing as first class features.

Let it be noticed that mobile apps do undo-ing very poorly, as well.

I've implemented multi-level undo/redo on both the desktop and the web, and the complexity is no different between the platforms. Client/server is a red herring, because what kills you is unexpected state changes, and a desktop app has to contend with that as well (e.g. what if you want to undo a file delete but a file has been created with the same name by another app?)

The trick is to put everything in commands which keep track of the old ad the new state (or at least the parts you need), so that you can have a command history stack, and undo merely means "run the unexecute method of the command at the current position, and move the pointer to the previous command". If unexecute fails, you throw away all older commands (undo history). If execute fails during redo, you throw away all newer commands (redo history). Multi-level undo does need to be designed in from the start, but once you learn how it works it does not add that much complexity.

The reason that you don't see many web applications that implement this is because web development did not branch off from desktop development, but instead branched off from unix systems administration (by creating glorified shell scripting languages to output html pages, and gradually improving on that). Web developers never learned from their senior desktop developers how to implement a multi-level undo/redo using a command pattern, because the vast majority of web developers never had a senior desktop developer to learn from. I only learned it myself because I did have such a desktop development mentor. Mobile developers are typically repurposed web developers, so no surprise that it suffers from the same affliction.

Re: your 3rd paragraph: yes, I wanted to mention that in my original comment and forgot. Thanks for bringing it up.

A lot of our modern infrastructure comes from the almighty UNIX era- before GUIs had really become as mainstream as there are todays. In that era, things like "undo" were close to non-existent (there is no undo for `rm`- the GUI's "hack" to solve that is the "Recycle Bin" (which is also nonexistent on mobile, interestingly enough)).

A lot of our modern web tools are mere interfaces to those various Unix utilities (phpmyadmin, as mentioned by Sacha, is just a neat little HTML interface to mysqladmin), and thus can't do much to provide functionality that's missing at the source.

Many things will be impossible unless you delay the initial action. I mean, how do you really undo sending an email? You can't. What you do instead, and I'm guessing this is what gmail does, is to delay the sending for 15 seconds to give the user time to regret.

Seems like delaying the action will almost always be possible. Guess i could give the users the misconception that they can undo whenever they want, which is just..

IIRC, "it's not a feature, it's a bug". Engineers noticed it took about 15 seconds to send a mail through Gmail and added an option to cancel it.

No -- it's an artificially-added delay. By switching the option on, your emails are delayed by the time period you choose.

Sometimes the actual deletion must occur before a mistake is realized. I have often seen undo implemented as a 'soft' delete which means the read-side needs to be 'undo aware'. Sometimes undo is implemented by backing up all related data to a separate location which is also non-trivial. Managing the 'restore' half needs logic to account for conflicts and changed state.

It doesn't change the fact that Undo is an amazingly useful feature but its not always as simple as 'delay the action'.

If you're both using an Exchange server, you can undo sending an email. https://office.microsoft.com/en-us/outlook-help/how-message-...

There's nothing that makes internet somehow undo-hostile. But your observation about relational databases not having the support for undo is in the right track. Actually it can be expanded to most data storage mechanisms, sql, nosql etc. Out of the box many data storage systems don't support versioning and that guides the applications towards the "warn, overwrite, no undo" pattern. It's just a lot easier to do apps like that.

For many cases it would be better if the underlying data storage mechanism would support versioning. Image a CMS that's running on top of git. You'd have diffs, history, branching, merging, clones, tags and other very important features out of the box. Doing those features on top of a relational database is a lot of work, but with git you get them free.

REST could accomodate for undo quite fine. The server would just have to return a resource representing the action in the response. The client could then delete the action with another request, which would amount to an undo. This is analogous to the command pattern and would require more effort from the programmer, just like normal undo. You need to keep an action history and make sure that all actions are reversible.

If REST follows HATEOAS fully, the back button is 90% of your undo.

I would like to know more about this implementation. I don't see how going back after a POST action is related to HATEOS.

Hmm. This would require a representation of the complete state history in resource urls, wouldn't it? I can only come up with something like /image/edit1/edit2/edit3/edit4 where going back would bring you to /image/edit1/edit2/edit3.

I suppose you can also do something state-based like /image/state4 going back to /image/state3. This would push the storage of the edit stack to the server.

Is this what you mean?

Yes; with request / responses reanimating a continuation, and with a copy-on-write tree of activation records instead of a stack.

But the usability probably wouldn't be fantastic.

Hey, have you ever seen this thing called etherpad? it's pretty great. Some guys even took the research put into that and made a library anyone can use called shareJS[1]. It uses operational transforms, and yes, they're pretty hairy.. but they've been done, and now anyone can use that work.

Then you have the persistent data structures from clojure. Now I might be crazy, but it seems to me that those data structures are probably the most valuable contributions that language has made to our craft, and make the sort of things you're talking about-- not trivial, but a lot easier.

The whole trick is you have to start thinking 4-dimensionally- Which is difficult because our programming languages tend to have modify-in-place mutable state, when what we should have is variables that remember what they were at specific times, and algorithms that are able to merge conflicts seamlessly- not by locking but by recreating what would have happened if the two events had happened synchronously on the same system.

But then, you only really have to do that if what you're talking about is a multiuser system. You can do all this much easier if what you're willing to build is a simpler system. One that works like a one page JS app- JUST LIKE A DESKTOP APP, and only talks to the server at the point of "saving" or "synchronising" or whatever you want to call it. That's easy. You just program undo just like you do in a desktop app, and what you save to the server is a serialised history.

On the server, you have your git-like versioned databases for maximum undo. We know this can work because dropbox does it. If I delete a file on my machine... like REALLY delete it, dropbox still has it for 30 days.

Wikipedia articles have "infinite" undo.

And that's all web. that's all internats.

Fundamentally, once you have javascript, the html5 appcache, localStorage, what is the difference between the "web app" and the "native app" other than performance and some other native features irrelevant to undo?

the mobile apps still have to phone home to a server too now. Half the apps on the app store don't work without a net connection. What is the actual difference?

In fact, you could write a whole app that just downloads to the phone, runs entirely locally, doesn't talk to the server after the initial download, and runs in a browser. Why couldn't you have undo in that?

Well, why not. so I added it to my app pix.pe[2] when you press the back button. not exactly the most impressive example since you don't have much state to store... but what's the difference between doing it there, and doing the same thing in a native app? it's all just turing complete language code, with a storage mechanism and a way to draw on screen. Once you have those things there's nothing to stop you. Other than undo itself being kind of difficult already, regardless of what platform you're writing into.

[1]: http://sharejs.org/ [2]: http://pix.pe/

There is absolutely no problem implementing undo on the web with restful interfaces. I just built a quite complex data management application where almost anything is undoable in a very Photoshop way (you see the "History" pane in your UI and can undo whatever you desire). If something is not undoable there it's either a bug or NIY (not implemented yet).

The product is hardcore JS single page application backed by document oriented database, JSON, REST, buzz, buzz, buzz, etc.

How do you avoid that the users action have a cascading effect through the system? Was the undo/history option built in from the start?

For example, your app inserts a new doc, some other process sees the new doc and updates a table or inserted into a message queue, it gets picked up by Foo and..

Moreover, that other proces need not be on the same server, or even on a server that you control; worse, it could trigger a meatspace effect. "User now authorized, access granted, door opened. [five minutes pass] Oops, that was a mistake." How do you undo _that_?

Built from the start, yes.

and... what? you mean what would happen if I undo the creation of the doc? Like I was deleting the doc - the system either would not allow me because of the linked docs/events/objects or would do a cascade delete, if it can.

Meant and.. a cascading effect resulting in 100 other actions you're only half-aware of, maybe on other systems =) So building the whole system with this in mind is probably a good idea.

I don't think that undo has much to do with the type of app, but rather with its design. So mobile, web and desktop apps should be able to offer similar functionality. At least for delete many sites are using a deleted flag anyway, which should be easily reversable. Getting back even part of the content might be worthwile.

In your example, if user 1 doesn't see the edits of user 2 there's a bigger problem. Undo would be liniar.

Great points, I hadn't considered that angle while writing the post. Those are definitely hard problems to solve.

Famous last words. :)

> doesn’t seem like it would be that hard technically.

My philosophy is that of all the things that are important for a business or a web service - keeping your data is the very highest priority. Just about anything else can be fixed, but if your data is lost with no backup then no amount of programming or time or sweat is going to get it back.

It's a good idea to just keep this in mind when you're working anywhere near a production database. backup, backup, backup.

Backup is manual Undo.

On the one hand, I agree with the ideas here. On the other hand, it really worries me when I find out that some server doesn't delete the data when I tell it to delete it. For example, when you delete your Facebook profile or your mails on GMail, wouldn't you like that data to be utterly destroyed?

What would be the correct solution, the one that balances out both of these needs?

The correct solution would be to tell you what's happening.

"Your data will be deleted in 24 hours. You can undo this deletion at any time before then."

Gmail's "undo send" functionality faces a similar but different problem: once an email has actually been sent, there is no way to undo it. They way they solve that is by letting you configure a delay, so you have some period of time in which the email hasn't actually been sent yet so you can undo it.

Something similar could work here. When you delete some data, it gets soft deleted (still exists in your database/etc, but is considered deleted by the application). After a matter of minutes (hours?), it gets actually deleted. You've got a grace period in which you can undo the delete, and then it's gone forever.

Since the most common use case for an 'undo' feature is undoing something you did very recently, that should strike a good balance.

Presumably something similar to the Gmail "Undo Send" example? Time limited reversal (in this case specified by user preference) to give you at least some amount of time to reverse your actions before they become permanent.

It's 5/10/20/30 seconds for an email, which seems like a good fit for that use case. Perhaps a Facebook profile delete or mail delete might be more like a 5 min/1 hour/1 day option set, since it doesn't interfere with the primary purpose (i.e. I wouldn't want to wait an hour for all my emails to get sent, but I might be OK waiting an hour for them to actually delete).

It's worth noting here, the two instances where the author wished for an "undo" (dropping a data database table and deleting a production server) are very different from what the rest of the article discusses (user-facing apps like Gmail, Photoshop).

A database or IaaS application are typically used by administrators, and typically every action is rehearsed in the form of staging testing or automated tests. Furthermore, these types of applications would need significant additions or rearchitecture to account for undo operations.

For example a SQL implementation might not be able to reclaim disk space as well if it were unable to really delete the data from a dropped table. Likewise an infrastructure platform would need to keep unused resources busy. In both systems there are important ramifications of the deletion, and providing the ability to undo them doesn't exactly make sense.

It is true though that some of these cloud services should offer some way to enable an extra level before deleting. Azure, for instance, makes it quite easy to nuke a database or storage pool. I'd really prefer if there was a forced sign-in again for such rare options. IIRC, AWS has a 2FA option for deleting S3 buckets or something.

As for databases, always have BEGIN TRAN at the beginning of any commands, with a commented out COMMIT.

Easier to implement this if your data is backed by Datomic. I'm working in a HIPAA environment and we're quite happily using Datomic there.

That's interesting. Do you have any "really delete this data" requirements and if so, is it hard to deal with that with Datomic?

(sorry if question is dumb, I have near zero knowledge on both HIPAA and Datomic)

Excision is built into Datomic expressly for this purpose.

I don't know why people assume those capable of building a database would also fail to anticipate this need.

The difference is that you don't use excision except in special cases (like legal obligation to delete data), you use retraction which doesn't lose any history.

Thank you for sharing your experience.

> I don't know why people assume those capable of building a database would also fail to anticipate this need.

Praptak asked if it was hard to deal with and did not imply Datomic's developers failed to anticipate the need.

Excision is a feature that must be prioritized like any other and in fact was not available until Datomic 0.8.3941.


3941 was pretty early in Datomic's lifecycle so far. It's still a young product but it's very practical already.

Fair point. :)

We provide a timesheet web app. And didn't want save/submit buttons. Auto-saving the data as users type.

To alleviate this change for business users, we decided to build an Undo, and a Redo, for most user actions.

With a similar technique, by storing the action and it's reverse in 2 stacks. And moving them from one stack to the other.

It was quite hard to implement together with an auto-saving of the data.

But after 3 years of operations, the undo/redo is barely used. And we get requests from users who clearly didn't see it. Or don't imagine it is possible.

While I was really happy seeing it working on a web app. I'm not sure it was worth the effort, and the additional complexity to save data.

This is funny, as in my career I've seen a number of domains, and built (web) systems which required a form of undo. You just don't see it too often in the PHP/Ruby crowd because it's hard to get right and each implementation has inherent limitations.

Luckily there has been work on patterns since the CoF Command/Memento: the Event Sourcing pattern (http://martinfowler.com/eaaDev/EventSourcing.html) can be used to implement system-wide undo functionality.

I've worked on event sourcing based systems, Datomic is a lot saner.

We here at Webflow went through great lengths to implement the command pattern in our web designer. It has definitely paid off when we tell our users they can just hit Cmd+Z and Cmd+Shift+Z anytime they make a mistake.

That said, it's really difficult for webapps to fully support undo/redo. A lot of the web is transactional, and different actions trigger follow on actions. GMail does a really good job with its undo, but there's a reason it goes away after 10, 15 seconds!

Undo is hard, not a core competency for most companies, and most users don't care. In fact, many users don't want deletes to be undoable, they want deletes to be delete.

You could probably make a stronger case for improving deletes by overwriting the disk space with garbage and ensuring users that no derivatives were left around. That would be a selling point.

Imagine SnapChat with undo...

Undo is hard? With web apps most developers complain that it's actually too hard to delete things so they use a delete flag instead...

Delete can be hard too...

Undo is definitely harder.

Implementing bug free undo is difficult, in my experience. I have a gut feeling that functional programming has a lot to offer here.

CouchDB supports undo as part of their core storage model. http://guide.couchdb.org/draft/btree.html

The short answer is that because CouchDB uses append-only files, the B-tree root node must be rewritten every time the file is updated. However, old portions of the file will never change, so every old B-tree root, should you happen to have a pointer to it, will also point to a consistent snapshot of the database.

Doesn't that mean a rollback of the entire database, as opposed to just a single operation?

This isn't a web thing, it's a technology thing. If you dropped a database via a command line tool or desktop app, you'd still lose everything. It's not phpMyAdmin -nor any other web app- being lazy, it's just how that technology works.

And I think the argument that you can't blame the users isn't fair because these are sysadmin tools - so you'd expect the users to know what they're doing.

"That's how technology works" because that's how the specific bits of technology we're talking about have been implemented. We make the technology, and we could make it work differently. There are cases where un-undoable commands are useful, but these cases are only a small fraction of the things we do on computers, sysadmins or not. Sysadmins may "know what they're doing" but they make mistakes like anyone else, and software should, where possible, be designed to reduce the impact of those mistakes.

Software is designed to reduce the impact of those mistakes - that's where back ups, file system snapshots and virtualisation / OS containers come in.

Some database operations do have an undo command per session; up until a commit is made. But it makes no sense to have an undo for drop database, which is why it auto-commits.

Sometimes the "undo" command needs to run a layer or two lower down in the stack than on the application layer. 9/10 times, there is an undo command (assuming the platform is installed correctly) - and as the author noted, he had a backups so that would have been his "undo".

So while I'm all for building safety nets and better tools; I also think the OP is being completely unreasonable expecting every sysadmin application to have an inbuilt "undo" command. Sometimes "undo" tools need to be worked into another layer of software lower down the stack - but just because they don't exist in the GUI frontend of choice, it doesn't mean that they don't exist at all.

But that's just my opinion as someone who also constantly makes mistakes hehehe

> it's just how that technology works

I think we can fix that! You're right that some things aren't amenable to a literal "Ctrl Z"---but I think Sacha's underlying point is spot on.

Many "irrevocable" actions could, with better design, be made made safe.

For example, Sacha's second story was where he accidentally deleted a production server instance. With a typical VPS, his configuration might be irrevocably gone, and he has to manually recreate everything under time pressure. But if next time he uses, for example, a Docker host, then such an error will be as simple to fix as deploying the same image again.

Another good example is Git. With most version control systems, "rebasing" is either unsupported or discouraged, and if you mess up, you can lose data permanently. Git's design is undo-friendly from the ground up: any commit hash encodes the exact state of your repo, including history all the way back to your first commit. So even if you rebase or force push and make a terrible mistake, you can nearly always use `git reflog` and get things back just as they were. Also, unlike some lesser VCSs, Git is transactional---so if you say "git pull" and then trip over the power cord while it's updating, your repo will still be in a good state afterward.

Technology that has a simple, explicit concept of state--such as Docker images or Git commits--is fundamentally nicer to work with. You can explore and experiment, and if things go wrong, you can roll back with confidence.

Well this is the thing, there are layers of software to recover (or "undo") from silly mistakes. Even with the phpMyAdmin example, he had backups. I don't think there's a lack of undo utilities, it's more a case that tools to undo sysadmin mistakes are often another layer of software lower down in the stack.

The docker example is a great one though. Lately I've been doing a lot of work with FreeBSD and using Jails (which, if you weren't already aware, are OS level containers for FreeBSD). And using ZFS to snapshot the Jail. I've worked with virtual machines before, but I just love the ability to take snapshots of an environment before making potentially dangerous changes.

It's probably also worth noting that some of authors examples also demonstrate why you should be using root access for every day operations.

The thing is, I do relate to the point he's making, but it also feels a little like he's blaming application developers for his own mistakes (using root access for general usage, not backing up config files nor snapshots, etc). So while I think it's great that tools are getting better and easier to use, we also need to be careful not to depend on these things to save us from our own laziness. Because that level of complacency will lead to more mistakes than if the tools required our greater concentration (as the adage goes: "the more idiot proof you make something, the bigger the idiot that comes along")

For FogBugz and Kiln, we try to follow the principle that changes should always be reversible. Clicking "delete" on something just marks it as deleted, for example, with a corresponding "undelete" action hidden somewhere administrators can find it. If you want to truly delete something, you have to get in contact with our customer service folks (sometimes to our users' chagrin).

"every undoable action first needs to be represented by an object in your code. This is called the Command Pattern"

This is too OO for my taste. Having just seen a talk about MiniKanren, I wonder if you can implement undo effectively with a relational (logic) programming system. Is anyone aware of research (or practice) to that effect? My googling isn't turning up anything relevant.

Cocoa offers the same undo implementation as described here with "NSUndoManager" where, for each action, you add the opposite action to an undo stack.

As a pattern it is proven to work. It just consumes memory and servers might not scale as well as a desktop app in this regard.

If the undo/redo stacks don't grow too long and the operations are simple enough in nature it might work though.

I was thinking about how memory must work to allow "Undo" on desktop apps earlier today, and realizing how different that is as it pertains to the web. Undo is amazing, it's a life saver - it's probably literally saved me days of my life when I've accidentally deleted entire projects before.

"Destroys privacy by posting tons of selfies"


I just tried sending a message in Gmail, and it didn't give me an option to undo. Is it a feature I have to enable?

You're right, it's actually a "labs" feature: https://support.google.com/mail/answer/1284885?hl=en

Never thought about it. The concept is interesting.

Interesting concept.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact