I frequently fall into a sort of working anti-pattern involving “rabbit holes.”¹
Here’s the form it takes (with a concrete e.g. in parentheses):
- Start working on something (the “real task”)
- Discover a misconfiguration related to the task (the Emacs mode for working with the files involved in the “real task” isn’t installed)
- Start fixing the misconfiguration, but run into an issue (there’s a dependency for that Emacs mode that doesn’t seem to have been ported to my OS)
- Begin dealing with the issue (port the dependency to my OS)
- Run into a problem with the issue (the dependency uses a system call that’s ambiguous on the new OS)
- Research the problem (hand-trace the dependency, look at manuals for the old and new OS, figure out how to fix it)
- Fix the problem (fork and commit my patch)
- Share my fix with the community (create a pull request)
- Try to remember why, exactly, I just spent an hour researching an arcane OS issue that has nothing to do with the “real task”
- Give up trying to remember, and return to #1 (the “real task”)
- Discover #2 again (I need a new Emacs module installed)
- Discover #3 again
- Continue until I forget one of the remaining tasks completely, or the workday ends (which will guarantee I’ll forget where I was by tomorrow).
I’d very much like an always available “what I’m working on now” stack — that way, when I get into this pattern, at step #6, I’ll have the following in a buffer, where the bottom item is always the one I’m working on now:
- Real task - Install foo-mode - Install libfoo dependency - Port libfoo to MyOS - Figure out what’s wrong with funcFoo
Then, once I complete the “figuring out” task—here, I’ve gone ahead and added a couple tasks (testing and submitting a patch) I know I’ll have to handle after I finish the one I’m on (fixing the code):
- Real task - Install foo-mode - Install libfoo dependency - Port libfoo to MyOS - Submit PR to libfoo maintainers - Test funcFoo - Fix funcFoo
Then when I’ve fixed
funcFoo, I “pop” the stack to:
- Real task - Install foo-mode - Install libfoo dependency - Port libfoo to MyOS - Submit PR to libfoo maintainers - Test funcFoo
and I know I need to test it. Once I’ve tested it, I “pop” again and know I need to submit a pull request.
Once that’s done, I “pop” again, and my new “right now task” is
Port libfoo to MyOS. Let’s say I’m lucky and
funcFoo was the only blocker to porting. Then that’s already done, so I “pop” again to
Install libfoo dependency.
I install the dependency, which gets me back to:
- Real task - Install foo-mode
foo-mode but then when I run M-x
foo-mode RET, it doesn’t work right:
- Real task - Configure foo-mode
Some more items probably get pushed and popped as I look into various options and configure them, but eventually, I’ve configured my new mode, popped that off the stack, and have:
- Real task
By tracking why I keep “rabbit-holing”, maybe I can avoid the cautionary tale:
So: is there an straightforward way to get something like what I’ve described from Emacs—most likely, with Org?
It’s a little like capture, it’s a little like agenda, it’s a little like clocking, and it’s a lot like nested outlines.² But, if any one of those is satisfactory for this purpose, I don’t know how to configure it to be so—the defaults aren’t this.
Ideally, I want the always-on availability of capture with the ability to quickly pop up and dismiss an “objective HUD” window, with the top of the stack (what I should be doing right now or the blocker to doing that) visible (the bottom of the task list in the format I used above).
The quick-and-dirty way would be to just create a single global org document (maybe
now.org), put a plain nested list into it, create an interactive function that visits the
now.org buffer in a small window, and bind that interactive to a global key—then call it done.
This being lightweight, ubiquitously available, and as near to frictionless as possible are the most important things. I can “manage projects” just fine, with Org or other tools, when I know ahead of time the tasks required for completion. What gets me is those times when a “this will just take a minute” diversion³ turns into something much longer, and begins to spawn mini-subprojects of its own.
So, is there a better way than that quick-and-dirty plain outline option?
It would be nice to have an “add yet another item right below (in the stack) the current one to remember to do later” command reading from the minibuffer (e.g. for reminding me to make sure I’m tracking the right branch before I try to create a pull request or other such nonsense I want to remind my future self of), a way to context-switch so that the entire rabbit hole is saved for later while I work on something else (during which, I can undoubtedly fall into a brand new rabbit hole so I need to save that too), etc.
Saving but hiding done items for later consideration rather than killing them would be nice, too, but remembering to type [SPACE] or some keychord so I can just use checkbox filtering is more friction. (Property tags with speed keys to quickly add
:done, and a sparse tree view filtering them out, perhaps?)
It’s possible Org isn’t even the right solution here. I’m open to trying something else. I don’t mind hacking up my own solution, and I know how I could (the quick-and-dirty way, anyway)—I just don’t want to needlessly reinvent a wheel.
¹ Here I define “rabbit hole” as: a series of one or more unexpected subtasks, formulated and commenced in the course of doing another (planned) task, that take longer (often much longer) to complete than originally expected. This definition differs from the colloquial one in two important ways: a rabbit hole in this sense may involve subtasks absolutely necessary to complete the larger task; and it may take an amount of time that, while differing greatly from the pre-task time estimate, seems perfectly justified and reasonable—in retrospect. In order to emphasize that the rabbit hole was not optional or from a lack of discipline, some engineers call this “dependency Hell” instead.
² Actually, it’s exactly like nested outlining—except it goes inside-to-out, bottom-to-top. Chronologically, flipping it all around, it’s:
- Fix funcFoo - Test funcFoo - Submit PR to libfoo maintainers - Port libfoo to MyOS - Install libfoo dependency - Install foo-mode - Real task
but, unfortunately, neither outline-mode nor Org will let you do this trivially.
³ I’ve used GTD apps that had task chaining (a.k.a. “dependencies” or “gating items” or “blockers”) for this before, and it works in theory, but it adds enough friction that I won’t use it to track “doing something really quick” right now. David Allen himself said that you shouldn’t bother capturing tasks you can take care of in less than two minutes; just do them. The problem is when the little task turns out to be nothing close to two minutes once you’re doing it, or spawns a succession of little subtasks such that solving the diversion takes the mind away from solving the real task.