
Undo - sgdesign
http://sachagreif.com/undo/
======
tadfisher
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.

~~~
sgdesign
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.

~~~
reneky
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.

------
brianberns
"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.

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

~~~
Legion
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_.

~~~
uniclaude
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.

------
kcorbitt
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](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](http://railscasts.com/episodes/255-undo-with-paper-trail)).

------
vcherubini
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.

~~~
smooj
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.

~~~
jd007
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.

~~~
mcphage
> 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?!

~~~
dandelany
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...](http://en.wikipedia.org/wiki/Directive_95/46/EC_on_the_protection_of_personal_data)

In the UK, for example, this is implemented by the Data Protection Act 1998:
[http://en.wikipedia.org/wiki/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_...](http://www.ico.org.uk/for_organisations/data_protection/the_guide/information_standards/~/media/documents/library/Data_Protection/Practical_application/deleting_personal_data.ashx)

"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...

~~~
mcphage
> 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".

~~~
dandelany
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.

------
raimondious
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](http://alistapart.com/article/neveruseawarning)

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

------
GuiA
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.

~~~
gizzlon
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..

~~~
joshguthrie
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.

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

------
joshmlewis
Famous last words. :)

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

------
jakejake
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.

~~~
vdm
Backup is manual Undo.

------
CodeMage
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?

~~~
cgmorton
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."

------
apeace
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.

~~~
MichaelGG
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.

------
coolsunglasses
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.

~~~
praptak
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)

~~~
coolsunglasses
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.

~~~
alanning
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.

[https://groups.google.com/forum/#!topic/datomic/Gk8h6MrnJYs](https://groups.google.com/forum/#!topic/datomic/Gk8h6MrnJYs)

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

Fair point. :)

------
tchvil
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.

------
radicalbyte
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](http://martinfowler.com/eaaDev/EventSourcing.html))
can be used to implement system-wide undo functionality.

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

------
brryant
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!

------
crystaln
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...

~~~
blub
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...

~~~
crystaln
Delete can be hard too...

Undo is definitely harder.

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

------
j_s
CouchDB supports undo as part of their core storage model.
[http://guide.couchdb.org/draft/btree.html](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._

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

------
laumars
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.

~~~
voyou
"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.

~~~
laumars
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

------
krallja
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).

------
graue
" _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.

------
jayfuerstenberg
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.

------
tomasien
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.

------
AlexanderDhoore
"Destroys privacy by posting tons of selfies"

UNDO UNDO UNDO

------
trevordixon
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?

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

------
fivesquare
Never thought about it. The concept is interesting.

------
fivesquare
Interesting concept.

