Virtual desktops ....
  I always thought this would be useful for switching 
  between different contexts, like work vs. personal, 
  but Ive rarely used it in practice.
I'm a virtual desktop addict. If I may, I'd like to share how I use mine, so that you might perhaps find them more useful in your own work. I have dual monitors, and four virtual desktops (in XFCE, but that doesn't matter).

Originally, I used only two workspaces (email/reading, development), and this has evolved a bit over time into 4. What I like about using virtual desktops is that I have a spatial mental model of where each thing is, which helps me ensure I don't mix up dev/production, and helps me avoid alt-tabbing to find what I want. I make extensive use of my window manager's ability to maximize on the left or right half of a screen. (This would probably not work well for me with a single monitor, unless it were a large one.)

1: E-mail/calendar on the left monitor, automated build system output on the right. This is for things that are semi-important but which I don't want to regularly have interrupting me.

2: Web browser with the app I currently am developing, and my console window on the left monitor, full-screen IDE (PyCharm) on the right. (I also put emacs or a terminal on the right as well when writing extensively in those.) This workspace is where I spend more than 80% of my time.

3: Github on the right screen, for pull requests, code review, issue tracking. I use this for a context-switch from developing code to reviewing it. I'll also use this workspace when babysitting a code release, to help ensure that I don't mix up local stuff with remote stuff.

4: music player. I stream music, so I rarely need to look at this except to change channels.

I used to navigate workspaces spatially too, but then I increased to three monitors and the traditional workspace model broke down big time. Namely, switching to a different workspace switched whatever was displayed on all of my monitors. I couldn't easily compose groups of windows onto my displays.

The solution (for me) was to throw out a spatial representation of workspaces and adopt a more dynamic approach. Instead of being fixed to a set of N workspaces in a particular geometry, I switched to having a fluid list of named workspaces. What makes this work particularly well on multiple monitors is that each workspace can be viewed on any monitor. So for example, with three monitors, I have three workspaces visible at any point in time. And yes, I can flip the workspace on one monitor to the other monitor.

This ends up being great for my work flow, since I can maintain my work area for any particular project without cluttering up the rest of my desktop. For example, when I'm working on the window manager that implements this functionality, I might have a workspace called "wingo" for code. And when I want to switch back to working on the X client library for Go, I go to my workspace "xgb" and it has me right where I left off.

And of course, I have workspaces like "browser", "mail", "irc", etc. I have some temporary workspaces too, which are used for scratch work.

Any workspace can be removed. And I can add a new workspace with any name at any time.

If you're interested, this is all implemented in my hybrid stacking/tiling window manager: https://github.com/BurntSushi/wingo

(Similar features exist in i3 and xmonad, but both are emphatically tiling window managers.)