About
This is the M Cubed Software weblog. To find out more about us head to our about page.
Search
Feed
Archives
- June 2010
- April 2010
- March 2010
- February 2010
- January 2010
- November 2009
- August 2009
- July 2009
- May 2009
- April 2009
- March 2009
- February 2009
- January 2009
- December 2008
- November 2008
- October 2008
- September 2008
- August 2008
- July 2008
- June 2008
- May 2008
- April 2008
- March 2008
- January 2008
- December 2007
- November 2007
- October 2007
- September 2007
- August 2007
- July 2007
- June 2007
- May 2007
Version Control UI Design
Posted on 12/02/2010 at 12:01 PM in Coding
As with many of my blog posts, it is often a tweet or another blog post that made me want to write my thoughts. In this case it is both:
Just accidentally blew away 16 files' & days' worth of work with hg. Looked up, TIme Machine had just finished. Lost < 1 min. of work.
- @incanus77
That tweet prompted Wolf Rentzsch to write this post about how Time Machine is your version control "safety net". To me both of these are shocking. It seems that the tweeted mishap may have been user error, but it made me look into how the various user interfaces help protect the user.
Your VCS should protect you
For a long while I was opposed to VCSs, mostly due to faffing around with subversion and getting nowhere. With DVCSs I've become an addict. The issue is that DVCSs also try to be clever. Their primary goal is to protect you from yourself, to make sure your code and its history are safe. Essentially your commit history should be like a stack. 99% of the time you push onto the stack, rarely you need to pop off a stack. You can read the contents of the stack as you want. But you shouldn't be able to modify the internals of the stack.
This is why I consider the many rebase plugins/commands in DVCSs to be harmful. I feel that rebase should be viewed as a mixture of goto, premature optimisation and Jeremy Kyle all rolled into one ie don't touch it unless you know what you're doing and are wearing many layers of protection, and even then it probably isn't such a good idea. Some people swear by rebase, but I feel that you shouldn't be messing with what should be treated as sacred.
Your repository is not a toy, so stop playing with it.
Protecting against destructive actions
This is where we get onto UI. I've never really given much thought to command line UIs, but comparing git, Mercurial and Bazaar I've found subtle differences in the UI that make it harder or easier for a user to perform a destructive action. These really fall into 3 categories: confirmations, making it hard to destroy and separating destructive actions.
In the case of the tweet at the start, I looked into the command that was performed: hg update -C . It offers no confirmation dialogue, it just cleans out the items that have changed. It doesn't make it hard to destroy changes and it is a one character option which means it is easy to do. I'm not sure about git but the equivalent in Bazaar would be bzr revert --no-backup. Of course there's no real reason to run --no-backup, it helps save your arse just in case and cleaning it up is just a case of bzr clean-tree --detritus (which lists the files to be deleted and asks for a confirmation).
One of the other examples is from the blog post. git branch -d abranch will delete the branch called abranch. Now to me this seems incredibly dangerous as there isn't any confirmation given. Occasionally I've seen warnings to use the uppercase -D option if changes aren't merged into the parent, but sometimes even those may not appear. If you're doing something like deleting a branch then it should be made harder to do. Really it should be git branch --delete-branch abranch and then ask you to confirm the delete.
Destructive actions should really be moved out into other commands if possible. bzr has 2 such commands: uncommit and clean-tree. Uncommit and clean-tree both list the items that will be removed and ask you to confirm. This makes the user double check what they're doing to confirm what they are doing. Now these commands could be moved into other commands. Uncommit could be made into bzr commit -d, but by separating them out you are making the user think that this is a different thing and making it harder for them.
The hypocrisy of UI design
It does seem very hypocritical, when most of UI design is a push to make life easier for a user, to advocate making it harder. But as odd as it may seem, making something harder may make it more usable. Now by harder I don't mean make a series of convoluted steps that require an animal sacrifice. I mean add an extra step to any potentially dangerous action. Tell the user exactly what the result of the action will be and ask them to confirm it.
Obviously you should provide undo when possible, but sometimes it isn't. Think about where in your UI you place these actions and consider whether you need them there at all. Don't put a 'wipe library' button right next to one of the most commonly used buttons in your UI, and no matter where you put it, if you can't offer an undo then tell the user exactly what you will do and make them confirm. Force them to pay attention to what they are doing. They'll thank you for it, even if it is just by not complaining to you (or worse to the internet) about how your software lost their data without warning.
(3) Comments
Comments
Good post. I also read that original tweet and had a rather visceral reaction as well. But my negative reaction wasn’t focused on a failure of tools, it was focused on a developer failure.
A few points:
- For clarification, regarding ‘git branch -d branchname’. This will *never* delete the contents of a branch unless those commits exist in their entirety on another branch. ‘git branch -D branchname’ is when you want to force deletion of the branch and potentially destroy its contents.
- How is it that days of work were potentially lost? Remember, the ‘D’ in DVCS stands for ‘Distributed’. Developers should be working on local repositories that are connected to a remote version of that repo. For example, with Git, I am never more than a ‘git push’ away from having a complete and perfect copy of my repo on a remote server. Doing simple pushes to a remote repo will guard against pretty much any disaster scenario. The only exception I can think of is if the dev is not making continuous and fine grained commits to their local repo. If the dev works on a ‘patch bomb’ than contains days of uncommitted work, then they deserve what they get. This goes against all best practices for development, and for using a DVCS.
- All of the major DVCS tools out there are fully network aware and designed to create pristine, cryptographically verifiable, clones of themselves across a network. Relying on Time Machine is fine as a final backup, but a few basic tips render this type of backup unnecessary:
a) Do your dev as a series of small commits, each leading you towards the final goal.
b) Push your commits to a remote server frequently.
- Finally, the suggestion that the tools are immature enough that doing something like creating an automatic tarball, or forcing a TM backup of the repo on every commit is ridiculous. Speaking for Git, at its heart is has a stated goal of never losing data. Its actually very hard to force Git to remove data (whether committed or not) and you have to be explicit to do it. Just learn the tool, and use its distributed facilities, and it will treat you right.
Cheers,
Glenn
Posted by Glenn Rempe on 12/02/2010 at 07:29 PM
I’m not sure how Mercurial and Bazaar work, but a further note about `git branch -d <branchName>` is that it doesn’t actually delete the contents of the commits, but rather just the “references” to those commits.
In fact, this is true for all git commands. They just create new commit objects as necessary, and drop the references to the old ones. The actual contents of the old commit objects don’t get deleted until `git gc` cleans them up, usually a few months later. Until then, you can use `git reflog` to help you find recent “unreferenced” commits. Or, the deep fallback is `git fsck—unreachable` plus a bunch of `git show <object>`s (to see the contents of those commit objects).
Those tools seem like a pretty good safety net to me (and have definitely saved me a few times).
Posted by Kelan Champagne on 13/02/2010 at 02:52 AM
@Glenn:
a) is swell, but easy to forget to do when you’re in the ‘zone’, and often the act of remembering to do it—and then doing the commit—takes you out of the ‘zone’. Productivity killer.
b) is tantamount to TimeMachine, in a sense.
I used git on my last project because we wanted to try it out just to see. I thought it was a timesink with no measurable benefits over subversion.
In fact, the visualization tools were far worse, the integration with Xcode was non existent and even the simplest tasks, like comparing the current version of a file to the latest committed version, was so much work compared to using subversion from within Xcode that I’d have to give the overall experiment a big FAIL.
This all might sound off-topic, but it’s all to do with the UI in the dev toolchain that keeps you (me) aware of what’s going on, what’s about to happen if i do a thing, warnings if I’m about to do something destructive, and keeping me from having to leave the context of my code editing and move over to a command line (for god’s sake, in this day and age) just to remember to do the 3-step to push out my changes so others in the team can pick them up.
Whereas access to a subversion repo on a webdav server would have covered 99+% of the functionality we needed.