Inbox Zero

Wed 15 May 2019 by Moshe Zadka

I am the parent of two young kids. It is easy to sink into random stuff, and not follow up on goals. Strict time management and prioritization means I get to work on open source projects, write programming books and update my blog with a decent cadence. Since a lot of people were asking me how to do it, I wanted to share my methodology. The following is descriptive, not prescriptive.

One thing I am proud of is that the initial draft for the post was written a year ago. I have done my edits for clarity, but found that my description of the process, for the most part, has remained the same. This made me confident that it is time to publish: this process has existed in its current form for at least a year, and I believe almost two years. This is not some fad diet for me: this process has proved its worth.

Glyph has already written at length about how a full Inbox is a sign of misprioritized tasks. Saying "no" is one example (in other words, prioritizing away). But when saying "yes", it is a good idea to know when it can be done, when should you give up, and potentially apologize, and when should you give a heads-up that it is being delayed.

His description, being more high-level, is prescriptive. The follow-up is the process I use, shaped by those general ideas.

The tool I use is TODOist. The first time I tried it, I decided it lacked some necessary features. I still feel this way -- about the free version. The free version is completely unusable. The premium version is perfectly usable.

The salient features of TODOist, that the rest of the explanation depends on, are:

  • Android integration. I use Android on my phone, and depend on good phone support. TODOist has a widget which lets me add a task without waiting for an app-launch. It integrates with Google Assistant -- it is possible to configure all "Note to self" to be new task creations. Finally, it integrates with the "Share" menu, so sharing things can create tasks.
  • E-mail integration: a customized e-mail address which opens a task for each e-mail
  • Browser plugin: add a task without opening the site, as well as "Add website as task" for current page.
  • A task can have arbitrary attachments.

E-mail scan process

I read e-mail "when I get around to it". Usually several times a day. I do have notifications enabled on my phone, so I can easily see if the e-mail is urgent. Otherwise, I just ignore the notification.

When I do go through my e-mail, I follow the rules:

  • If it's obvious there is no task, archive
  • If it's something short, obvious and I have the time, do it and archive. However, if I find in the middle that I am wrong about it being short and obvious, I abort. Usually it is obvious if an e-mail will require a lengthy research project. The most common way of being wrong is when, while responding, I find myself getting too emotional. I have trained myself to consider this as a trigger for aborting.
  • Otherwise, I "Forward" and send it to the TODOist auto-task e-mail -- and then immediately archive. The forwarded message, having literally all the words in the original, is enough information to search for the original in my archive.

Browser

The only "permanently" open tabs in a browser should be "communication" tabs: FB messenger, whatsapp, slack, etc. If any other tab feels like it would be bad to close, create task from it. I verify that each tab is OK to close, or needs a task + close, by closing all non-communication tabs if the tabs become too small to read the titles (Chrome) or the tabs need scrolling (Firefox).

My usual research task takes several tabs (Python documentation, StackOverflow, GitHub pull requests, tickets and more), so tab accumulation happens naturally, thus triggering the garbage collection process.

Reviewing tasks

Clean triage

This is a daily task, to go to the filter "triage" and clean it out. The filter is defined as "not marked 'time permitting' and does not have a due date". Since tasks come in without marking or due date, this is a filter for tasks that come in. The task is "done" when the filter is empty. Any task that actually needs to get done will get Scheduled with a due date. Note that this due date is not a real "due": it is when I plan to do it. This will get determined based on the task, on my available time, and when other tasks got scheduled.

Otherwise, the task is marked "time permitting". This means, in real terms, that I will probably never get around to it. This is fine -- and it feels nicer than archiving or deleting the task. It allows me to be less FOMO when doing the triage.

Occasionally, an external trigger will rescue a task from the "time permitting" graveyard.

Rebalance

Rebalance means that I do not want to have an empty day, followed by an avalanche day: I'll be as carefree as the grasshopper that day, watch TV and frolic, and then drown in tasks the next.

I look ahead, and if I see a day with less than 5-6 tasks, I will move some tasks forward to get done sooner. I do not worry about the opposite. If there are too many tasks one day, they'll naturally get postponed.

Non-meta Tasks

I treat the due date as an "ETA". I try to do all tasks due a given day on that day. If there is an objective deadline, e.g. a CFP that closes on a date, that deadline will be in human readable form on the task.

If I am too tired, or cannot handle more load, I start rescheduling "today" tasks. This process will take into considersation the "objective" deadlines, if any. It will also take into account the subjective value of the task to me.

Any task that gets postponed "too many times" gets moved to "time permitting".

Dependencies

Humans are social creatures. Some tasks, I cannot do alone. For example, when publishing a blog post, I like to have some trusted people review it. This means that I need their feedback.

When I need something from someone, that's a task. The task is to use that thing. The due date is the date to poke them about the delivery of the thing. Because I try to build in a buffer, it allows me to be nice about it. I am endlessly patient, with e-mails asking "let me know how it is going".

Some people are also busy. If someone tells me "I'll give it to you in a week", I make a task to ask them about it in a week. If they deliver, they will never know: the task gets done when I get what I need. If not, I'll mention, gently, "hey, it's been a week, wondering if there's an update."

Some people, for good or bad reasons, do not deliver. Then I have the task of deciding what to do about it. Sometime I'll ask someone else for help. Sometime I'll do it myself. Sometime I'll drop it. Whatever it is, it was my explicit decision.

Spoon Management

If there are too many tasks, and I feel overwhelmed, I will start postponing any non-urgent tasks. Sometimes, this means I will postpone everything. If I lack the spoons, I lack the spoons. I do not feel guilt about it.

Summary

Inbox Zero is possible. Not only that. Inbox Zero, I have found, is easy. Doing everything I want to do is not easy. But the meta-process: deciding what I want to do, deciding what I am going to say "no" or flake on, that is easy.

This leads to less anxiety. I do what I can, and decide that this is enough. I am kind to myself. Be kind to yourself. Go Inbox Zero.

(Thanks to Shae Erisson for his feedback. Any issues that remain are my responsibility.)


Publishing a Book with Sphinx

Mon 08 April 2019 by Moshe Zadka

A while ago, I decided I wanted to self-publish a book on improving your Python skills. It was supposed to be short, sweet, and fairly inexpensive.

The journey was a success, but had some interesting twists along the way.

From the beginning, I knew what technology I wanted to write …

read more

A Local LRU Cache

Fri 29 March 2019 by Moshe Zadka

"It is a truth universally acknowledged, that a shared state in possession of mutability, must be in want of a bug." -- with apologies to Jane Austen

As Ms. Austen, and Henrik Eichenhardt, taught us, shared mutable state is the root of all evil.

Yet, the official documentation of functools tells …

read more

Don't Make It Callable

Wed 13 February 2019 by Moshe Zadka

There is a lot of code that overloads the __call__ method. This is the method that "calling" an object activates: something(x, y, z) will call something.__call__(x, y, z) if something is a member of a Python-defined class.

At first, like every operator overload, this seems like a …

read more

Staying Safe with Open Source

Thu 24 January 2019 by Moshe Zadka

A couple of months ago, a successful attack against the Node ecosystem resulted in stealing an undisclosed amount of bitcoins from CoPay wallets.

The technical flow of the attack is well-summarized by the NPM blog post. Quick summary:

  1. nodemon, a popular way to run Node applications, depends on event-stream.
  2. The …
read more

Checking in JSON

Tue 08 January 2019 by Moshe Zadka

JSON is a useful format. It might not be ideal for hand-editing, but it does have the benefit that it can be hand-edited, and it is easy enough to manipulate programmatically.

For this reason, it is likely that at some point or another, checking in a JSON file into your …

read more

Office Hours

Sat 08 December 2018 by Moshe Zadka

If you want to speak to me, 1-on-1, about anything, I want to be able to help. I am a busy person. I have commitments. But I will make the time to talk to you.

Why?

  • I want to help.
  • I think I'll enjoy it. I like talking to people …
read more

Common Mistakes about Generational Garbage Collection

Wed 28 November 2018 by Moshe Zadka

(Thanks to Nelson Elhage and Saivickna Raveendran for their feedback on earlier drafts. All mistakes that remain are mine.)

When talking about garbage collection, the notion of "generational collection" comes up. The usual motivation given for generational garbage collection is that "most objects die young". Therefore, we put the objects …

read more

The Conference That Was Almost Called "Pythaluma"

Wed 07 November 2018 by Moshe Zadka

As my friend Thursday said in her excellent talk (sadly, not up as of this time) naming things is important. Avoiding in-jokes is, in general, a good idea.

It is with mixed feelings, therefore, that my pun-loving heart reacted to Chris's disclosure that the most common suggestion was to call …

read more

Why No Dry Run?

Sat 06 October 2018 by Moshe Zadka

(Thanks to Brian for his feedback. All mistakes and omissions that remain are mine.)

Some commands have a --dry-run option, which simulates running the command but without taking effect. Sometimes the option exists for speed reasons: just pretending to do something is faster than doing it. However, more often this …

read more