Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> design your code to use undo rather than confirmation

I can think of two ways to implement undo.

1. Use flags in the database, this method has its own drawback since the entry is not really deleted but flagged as one.

2. Client side. Delay the actual delete request to the server.



The delete flag in the DB could be null or the date the delete was requested. You could batch the commit cleanup hourly giving a delete at least X hours before it's committed.


I think no one would implement it client side in practice; if the user clicks delete and immediately closes the browser, what happens to the action?


Do what Gmail does and say "actions are still pending" as confirm box...


One standard "undo" mechanism is to store a stack of actions (per user), with each action having a method to undo itself.


It depends on how you interpret “delete”. Most people seem to want to make it synonymous with “erase”, but it should really mean something like “forget”. In that case, it’s easy to see how you would implement “undo”: just drop all (root) references to the record(s) in question and collect as garbage at a certain time (in, say, 30 days).


Another standard way is with the command pattern, and using one "undo" stack, with another "redo stack". When you perform a command, a command object is pushed onto the "undo" stack. When you undo a command, it's popped off the stack, its undo() method is called, and it's pushed onto the "redo" stack. When you redo a command, it's popped off the redo stack, and executed. When you execute a new command (not an undo or redo) you push it onto the undo stack and clear out the redo stack.

See this SO question for further detail and links: http://stackoverflow.com/questions/701131/data-structure-use...


There actually is another way. Event-Sourcing. I've never seen this technique in my limited experience though, but theoretically this would be the optimal way to implement such a feature, and obviously has to be a engineering decision from the get-go.

Alternatively you could also have a very primitive form of version control : recycle-bin (edit: actually this is the same as point 1 =) )


See also Operational Transform[1]. There be dragons, though.

[1] http://en.wikipedia.org/wiki/Operational_transformation


I liked this part:

"Similarly, Joseph Gentle who is an ex Google Wave engineer and an author of the Share.JS library wrote: Unfortunately, implementing OT sucks. There's a million algorithms with different tradeoffs, mostly trapped in academic papers. The algorithms are really hard and time consuming to implement correctly. ... Wave took 2 years to write and if we rewrote it today, it would take almost as long to write a second time."


How would the Event-Sourcing method work?


A useful analogy might be how accounting ledgers work. You never really delete anything; you just keep appending records saying what you've done. The balance is just the sum of all those operations. (Ledgers are a bit special in that usually all the operations in a ledger are commutative (+/-), but other than that it seems a pretty good analogy.)


First you start treating each event/operation as a fundamental part of your problem. Each Event can then have a opposite reverting Event. So if you want to reverse an action, you can just apply the opposite event. You can also display a list of recent events that have taken place easily:

  - user X modified article Z
  - user Y deleted article Z (revert?)
Note that I've only studied this in passing, and have never applied this in practice, so I can't answer just how effective this could be. Also not really sure how this works when other actions have already taken place, or how you can detect if an event cannot be recovered from (if there is such a thing).


Could you just delay the COMMIT for a few minutes/seconds/until the user navigates away?

And if the user clicks UNDO, do a ROLLBACK?

Edit: Of course, if anything goes wrong before the COMMIT, you loose the transaction.


That's not really feasible in a real world environment where database connections are frequently re-used and user requests are very short lived.

Database transaction are like try/except blocks - designed to clean up unexpected situations instantly, not as a state mechanism.


Thank you for the answer and explanation!




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

Search: