This week I wrote myself a self-verifying todo list. Inspired by the loops of last week, I wanted to create a system that would keep me in the loop of getting what I want to do in a day|week|month, done.
What I ended up with is a program that checks whether I've done different tasks, and outputs a checklist in red and green. With a click of a button I can run it again.
It's hard to pin down, but while the outcomes is similar, this feels drastically different to me from just crossing an item off a checklist when I finish it. There's a greater sense of stability when something other than myself checks a thing is actually done. In some ways I suppose this is signalling I trust a program I write more than I trust myself.
Well, before we get too deep into that, let's talk about the technical details.
The first, and trickiest step to getting this thing working is figuring out how to think about the task I want to do in a way that's computationally verifiable. For some things this is simple. If I want to check if I've tweeted today, I can just use the twitter API. But how do I check whether I've meditated?
I decided I'd write another program which sets a timer, and at the end writes that I meditated for that time to a little database. Then, to check whether I've meditated or not that day, the program just reads from the database.
I had to slightly change my habit to get this to work easily, but I get many benefits in return. I have a database full of historical data, a small tool I can build on to enable more complex meditation routines if I want to. And of course, I have a self-verifying todo.
So I translate all the things I want to do into tasks like these. Then I write a program that verifies them. Then I need to run all these programs, and process their output.
I'm definitely abusing the tool a little bit. It's purpose built for getting feedback about your codebase, so it has lots of tools for mocking function calls so you don't have to depend on external systems. But in my case all I'm doing is checking external systems. But, because it's all just code, I can get away with it.
Well, just because I can get away with it doesn't mean I should. This may seem like a lot of work for an objectively simple thing. Let me try and convince you it's not entirely ridiculous.
First, I'm turning a task that I don't like (making routines and habits) into a task I can actually take pleasure in (programming!). This translation is one of the most useful tools I have to actually get things done.
Second, it makes finishing tasks fun! I don't know what it is, but seeing a program run and the output slowly turn green is incredibly satisfying.
Finally, I get a ton of things "for free". Like I mentioned earlier, making things computationally verifiable also makes them easy to track over time, and makes them very explicit. It also means I can track whether I actually do things over time, just by storing.
Okay well actually not quite. This is a bit of an unsolved problem for me. You see, time as I experience it doesn't map neatly to time as all the computers I'm working with understand it.
For me a day doesn't end until I go to bed, even if it's 4AM, it's still Sunday night, not Monday morning, and it's the end of the week, not the start of a new one. I still need to figure out a nice way of handling this in my tests.
There are lots more things to explore. I want to figure out all this time stuff, and then actually track my tasks over time. I want to add an abstract task list for one-off tasks instead of just things that repeat. I want to improve the output of the whole thing so it's nicer to look at, with loading animations and all.
I'm confident I can manage all this because it's all just code. I can get as complex as I want.
Writing a task list this way feels closer to the arbitrarily complex ways I actually work. The hope is I can walk the line, encoding complex tasks, but fitting them into a system that helps me actually do them. We'll see how it goes!