I'm a software person at Prodigy Education. I'm also into Pizza & Bread.

Scale to Zero with Fly.io Machines

 ·  Permalink

I’ve written a bunch of hobby apps over time that I use to keep my life moving forward. I’ve got some small side projects, like http.ist and Lemur that need web hosting. I also have utility apps that filter podcasts from podcast feeds, truncate my RSS news, or show me the swimming schedule for my local pool (their website was terrible).

I’ve been managing a Kubernetes cluster on DigitalOcean for this, but it feels like massive overkill in cost and resources. As an alternative, I’ve been looking at Fly.io, a Heroku-like PasS. Fly has been great for an easy single-command deployment.

In the past few months, Fly has started releasing the next generation of their platform: Fly Machines. They’re lightweight Firecracker VMs that boot quickly and are cheap to run. Fly Machines will eventually be used to provide all new features for Fly’s central app hosting service, but at the moment they don’t have all the bells-and-whistles niceties of Fly’s general development platform. I’m sure this will change over time. But, we can take advantage of them now with a few simple commands.

What’s powerful about Fly Machines today is that we can scale them down to zero and then save on cost while they’re idle. When a request comes in, they can scale up in roughly 300ms, serve traffic and then scale back down again. This makes them an excellent fit for hobby apps.

Let’s look at a sample app and how we’d do this with Fly.

First, you need to write your app. I’ve written cookiemonster that just yells “Cookie!” when you visit it. For Fly to scale the service down when idle, it looks for cases where the app has exited with a status code of 0. If the exit code is anything other than 0, Fly will assume that the app has crashed and will restart it. This is great, because the application developer has total control of when to mark the app as idle and shut it down.

To scale to zero in Node, it might look like this:

const express = require("express");
const app = express();

let lastRequest = Date.now();

app.get("/", (req, res) => {
  lastRequest = Date.now();


setInterval(() => {
  const oneMinute = 1000 * 60;
  if (Date.now() - lastRequest > oneMinute) {
    console.log("No more cookies.");
}, 1000 * 60 * 2);

If no one has made a request in the last two minutes, our setInterval check will detect it and exit the app. This can be improved with stuff like middleware, but that’s the general idea.

Deploying on Fly

To deploy this on Fly Machines, we can’t use the normal Fly.io steps (at least not yet, I’m sure it’s coming soon).

Instead we’ll do the following:

flyctl apps create cookiemonster --machines

This step creates an app “container” that holds our Fly Machine. It’s what you’ll see in the Fly.io dashboard.

By default, if you create an app with the above commands, it won’t have an IP address (and since these are web applications, we need them to have a public ip). So, we’ll run the following:

flyctl ips allocate-v4 -a cookiemonster
flyctl ips allocate-v6 -a cookiemonster

Then to deploy the app, we’ll run the following:

fly machine run . --app cookiemonster --port 443:3000/tcp:tls

This command does the heavy lifting. It will:

  • Look for a Dockerfile in the local directory
  • Build a docker image using a remote builder (you don’t even need Docker running locally)
  • Deploy the image to the image registry
  • Create a Fly Machine and host it in the cookiemonster app.
  • It’ll also open the external port 443 on the app to point at 3000 on the Fly Machine. If you need to handle non-https traffic, you’ll also want to do this for port 80.

When you run this command, it’ll give you back an id for the Fly Machine that it creates. You’ll need this to make changes (like pushing updates). If you lose it, it’s in the Fly.io dashboard inside your app under “Machines”.

When you want to update the app image, you can run:

fly machine update e148e453be6e89 --dockerfile Dockerfile

This will build the docker image again, push it, and then update the Fly Machine. This step is also really easy to add to CI pipelines.

If you want to view logs to watch the app boot or shut down, you can run:

flyctl logs --app cookiemonster

It will show the steps of the machine reserving resources, booting, and the stout of the app. When the app exits, it’ll helpfully report: “machine exited with exit code 0, not restarting”.

Cron Tasks

For cron tasks, you can also schedule Fly machines to wake up and run (hourly, daily, or monthly):

flyctl machine update e148e453be6e89 --schedule daily

Cron tasks don’t need the IP steps above. They’ll wake themselves up on the schedule, run their code, and then suspend.

Happy cheap hosting!

The Places of Mastodon

 ·  Permalink

I’ve spent a few days diving into Mastodon and the ActivityPub Fediverse. It’s new to me, but so far there’s a lot I like about it.

I’m one of those old people who are still mourning the loss of blogs. The internet moved onto Twitter, but I’ve always valued having my own place online to write, think, discuss, and archive my thoughts (this website has existed in some form since 2001). In the past few years, I’ve been using Micro.blog to bridge my blog with the world of Twitter by cross-posting (I like and recommend it).

Domain names are really powerful. They communicate something more than just where your content lives: the brand, identity, quality, values, or principles of your content. It’s where you’re coming from. When I write something at benjohnson.ca you know it’s just me. If I were writing from nytimes.com or gawker.com my writing would land a little differently (for better, or for worse).

This makes me fascinated by the power of Mastodon communities. On Twitter, your handle doesn’t communicate a dimension of place. Sure, there’s a verified badge (or… there was) and there are the eggs, but when you’re writing on Twitter you’re coming from Twitter — there’s no defined community or place behind you.

With Mastodon, you and your writing come from somewhere. That could be from a huge general community (@example@mastodon.social), a niche community (@example@spacelovers.up ), a personal domain (@elon@musk.com), a corporate entity (@maggie@nytimes.com), or some awful exclusive cryptobro haunt where you need to show your apes at the door to join (@bro@ohnomyapes.com).

If you had told me that a lot of people in 2022 would be moving to a social network based on a W3C standards-based federation protocol I would not have believed you. And I doubt everyone is going to jump ship from Twitter to Mastodon.

But, I’m having so much fun seeing a variety of domain names on the internet again.

Introducing RenamerThing

 ·  Permalink

I’ve been a devoted “Paperless” person since 2012. I first got started with the ideas in David Sparks’ Paperless book, and I’ve grown my systems and practice from there.

The goal is that all the documents I might need are digital, organized, and findable. And all the paper is shredded and out of my life (and house).

For every document that needs safekeeping, my process roughly looks like this:

  • I use a ScanSnap scanner to scan to an OCR’d PDF in a folder called “Action”.
  • I shred the paper. This fills me with glee.
  • Hazel detects the new file, renames it, and moves it to the proper folder based on its contents, if it can.
  • For all the files left that Hazel can’t handle automatically, I manually rename and move them.

This last step is annoying. In a scanning and shredding session I might have twenty or thirty files left over to rename. I have to look at the contents of each file and rename based on my naming scheme. I’m currently executing a will, which involves a lot of paper, so this problem has come up more often than normal.

I wrote an app to scratch this very particular itch.

RenamerThing is stupidly simple. Given a folder, it’ll list all the files in the folder. When you select one, it’ll show a QuickLook view of the file (the contents) and there’s a bar at the top to give the file a new name. There’s also some shortcuts for prefixing with dates.

It’s on the Mac App Store for free. I might consider adding more to it in the future, but consider this a minimally useful version. That said, I have no idea if this is useful to anyone else, but it was driving me nuts, so I hope maybe this can help someone else too.

RenamerThing Screenshot


 ·  Permalink

I’m years late to this party, but the Arduino is so cool.

I’m a software person. I have almost no hardware experience outside of a high school class decades ago where we built hardware logic gates.

But, my kiddo has been falling down the Ghostbusters rabbit hole and he really wanted to make a ghost trap with blinking lights, sounds, and doors that open. It sounded like a perfect excuse to learn some basic electronics.

I bought the Arduino Starter Kit for like $100 CDN and it came with:

  • A microcontroller
  • LEDs to blink
  • Piezoelectric buzzer for beeping
  • A servo to open the ghost trap (naturally)
  • Wires, resistors, LCD screens, and lots more

It also came with an amazing starter manual that walks you through several projects to gain understanding of the various components in the kit. There’s even YouTube videos if you want a more visual walkthrough.

The Arduino has an IDE for uploading code to the microcontroller. The language is it’s C/C++ with a really simple API for controlling the various pins on the board.

In about an hour we had figured out how to have blinking lights and beeping sounds in response to a button press. I’m really excited to see how impressive of a ghost trap we can build.

My software career has been writing code that runs on servers or in browsers. I have some empathy for the hardware, especially when I do things that tax it. But, there’s something tangibly different about code written for a server in the cloud versus code on the Arduino. It’s addicting to see your software change something in the physical world. I really recommend it to other software people.

1Password 8

 ·  Permalink

1Password’s major rationale for moving from AppKit to Electron has been speed of development. They want to ship fast, and they don’t want the cost of supporting another native platform in AppKit. Allen Pike has a great rundown on this argument:

Slow is a dangerous place for a product company to be. Slow product teams tend to be outcompeted by fast ones. We complain about how Figma and Slack don’t feel native, but why are most of us using Figma and Slack? We’re using them because they outbuilt and outcompeted their native competitors. There are so many things that could improve in these products, but they’re the best tools yet built for their purposes.

The major downside, of course, is bloat. More memory and bigger binaries are not ideal for an app that tends to run in the background all the time. And we all have examples of Electron apps that felt big and bloaty.

I figured I’d give the beta a shot when I installed 1Password on my new MacBook Pro. And, I gotta say, I like it better. 1Password was an app that always had a lot of custom UI. They made that UI work with AppKit, but the Electron version feels more solid. It feels less like the ground is going to shift from underneath you. It’s possible (likely?) that this is the result of quality design work and not solely because of the framework, but if we needed to sacrifice to the Electron gods to get this design, I think it’s worth it.

I haven’t noticed any performance lag. Of course, it helps that this MacBook Pro is a ridiculous machine.

My biggest annoyance with it continues to be what is also the most obvious characteristic of Electron apps: immovable modals. Preferences modals are always locked in the middle of the primary window with some custom dimming going on behind them. This is when it feels the most like a non-native web app.

But, I’ll take that tradeoff for a serious design improvement to an app I use every day.

The Highlights

 ·  Permalink

A few years ago my wife bought me a Kindle for my birthday, and I converted all my reading to the Kindle. I love the e-ink screen. But the feature that I’ve grown to rely on is the highlighting.

I’ve never really been a highlight-while-reading person. In university it always shocked me to see people tarnishing the pages of their incredibly expensive textbooks with brilliant yellow highlights. But, of course, highlights made on a Kindle are digital and sync their way up into the Amazon cloud. The highlights are downloadable, storable, and are a great starting place for notes.

To this, I’ve added Readwise, a service that takes highlights to the next level. It collects highlights from the Kindle, API, and other sources. Every day, it sends an email with random highlights for spaced repetition. And it provides search, API access, and exporting of highlights and notes.

Beyond the Kindle, Readwise can also import highlights from services like Twitter and Instapaper. This means that all my highlights are in one place, my reading contributes to them, and the email digests help me make new connections by surfacing them.

This setup helps me feel like my reading is active. My ADD doesn’t get as distracted, and I’ve been finishing way more books than before. It’s a nice feeling contributing to a corpus that drives my future ability to recall what I have read.

Get Your Life Together With This Fridge Thing

 ·  Permalink

I was on Amazon looking for a replacement crisper bucket for my fridge. I did not find one.

But, some of these before and after photos are amazing.

Who stores their eggs in a pile at the bottom of a fridge?

Before and after scene. Before has a pile of eggs on the bottom of the fridge. After has an egg rack.

There is no way that the food on the left is the same as the food on the right. Someone has clearly become a healthier eater.

Before and after photo. Before has no colour and has a lot of food all wrapped in bags. After has fruit and healthy foods displayed in drawers.

The secret to keeping your fridge tidy is to throw out half of what’s in it. (There might be some truth in this one.)

Before and after. Before has lots of food in a fridge. After has only a few things badly photoshopped in.

Bring Back Captain Planet

 ·  Permalink

It’s been 31 years since Captain Planet and the Planeteers was on TV. It was somewhat influential to my upbringing. My childhood self had awareness that the planet could use some help and there was actually something people could do about it.

Now that I have a kiddo of my own, I’m wondering what it would be like if you revamped this for today. Some rough thoughts in no particular order:

  • Just make the whole thing about climate change.
  • Jeff Goldblum is still working and is crazy enough to agree to reprise his role as an enormous rat-based villain. (Maybe he’s anti-vax and so wasn’t vaccinated against the Great Rat Pandemic).
  • Whoopi Goldberg could still rock Gaia with her eyes closed.
  • The show should probably focus more on actual non-fiction issues than the original show. Maybe for a slightly older audience. But it could demonstrate the issues of the day the way The Magic School Bus demonstrates science.
  • We’ve come full circle enough that Captain Planet can keep the green mullet.
  • Greta Thunberg as Gaia’s assistant? She could just play herself.
  • The relevance for today is kind of shocking. The planet is in even more danger now. And while the original show was backed by data, there’s so much more of it to draw on for climate change. You could do a whole episode on how recycling doesn’t work as well as we think or a two parter on carbon capture.
  • Ma-Ti with the Power of Heart needs a revamp along the lines of Karamo from Queer Eye. On Queer Eye the guy who originally did “Soul” never knew what his role was so he would reorganize your CD collection. Modern Queer Eye figured out that the role is to make people cry. I don’t know what Heart does, but Ma-Ti needs some work.
  • In at least one episode they have to save the day without needing to call Captain Planet just to prove that we have agency without relying on magic (Captain Planet was inside us all along).
  • The Planeteers all need awesome vehicles so the show can sell a load of toys. Proceeds donated to help fight climate change.
  • The original show tried to dumb things down for kids by focusing on specific villains doing specific bad to the environment (Jeff Goldblum is dumping toxic waste again). I think for modern sensibilities we could get a lot more systemic. How is the deck stacked against the Planeteers? As You’re Wrong About would say: it was capitalism all along.

I could go on forever. Let’s inspire the next generation. The Power is Yours!

The Planeteers

Lou’s Rum Cake

 ·  Permalink

In April, my grandfather, Lou Siminovitch, passed after 100 incredible years.

He was famous in science circles for significant contributions to the study of genetics, the mentoring of hundreds of scientists, and sending letters to people to tell them how to do their jobs better. Later in life, the relationship he had with his wife provided fuel for the Siminovitch Prize in Theatre, the largest prize for theatre in Canada. He was honoured with the Order of Canada, the Flavelle Medal, and a slew of other awards. Personally, he had an incalculable impact on my worldview, ethics, motivations, and personality. He was a giant of a man.

But since he passed, the thing I keep thinking about is the rum cake. Of all his accomplishments, Lou wasn’t a great cook. It wasn’t an area that he was particularly interested in — a distraction from more critical pursuits. But he found himself in need of something he could bring to events he was invited to. Supposedly, some decades ago, my grandmother clipped a recipe for a rum cake out of a magazine and Lou made it ever since.

For as long as I can remember, he always had the ingredients to make this one cake on hand. They’re shelf stable, so they occasionally gathered dust. But if an event came up and he needed to bring something he’d whip up a rum cake the night before.

I don’t know why this is the thing that I’ve been thinking about the most since he passed. I think it’s just something that I loved about him. It’s so utilitarian and yet thoughtful. Lou was all about striving for excellence. But his focus wasn’t on being a world class chef, it was about being a world class scientist. He didn’t have a huge range he could draw from, but he could make this one excellent rum cake, and that would do. It allowed him to focus on the things that he really felt were important, while also sharing some joy.

And it really is a ridiculously excellent cake.

Lou’s Rum Cake


The recipe calls for having a Bundt pan. You can do it without one, but it’s much better (and more traditional) with one. And then you’ll be ready to make huge 60’s-style jello moulds.


  • 1 box of golden cake mix
  • 1 box of vanilla pudding
  • ½ cup of cold water
  • ½ cup of dark rum
  • ½ cup of oil
  • 4 eggs
  • 1 cup of pecans


  • ¼ cup of butter
  • 1 cup of sugar
  • ¼ cup of water
  • ¼ cup of dark rum


  1. Set oven to 350º F
  2. Grease and flour the Bundt pan.
  3. Place pecans at the bottom of the pan.
  4. Mix together all the cake ingredients and dump into the pan, and bake for one hour.
  5. About 15 minutes before the cake is done, make the glaze. Add the butter, sugar, and water into a pot. Bring to a boil while stirring vigorously. Boil for a few minutes and then take off the heat and add the rum.
  6. While the cake is still hot, poke a bunch of holes in the top with a knitting needle or a chopstick. You want enough holes that the glaze can drip into the cake, but not so many that when you turn the cake out it’ll fall apart. Drizzle the glaze over the cake (and into the holes).
  7. Allow the cake to cool and then turn out.

Some People Are Still Hurting

 ·  Permalink

This week my mind keeps floating back to a post written by Kottke from early in the pandemic:

Some people feel helpless & anxious.

Some people are bored.

Some people are self-quarantined alone and are lonely.

Some people are realizing that After will be very different from Before.

Some people are really enjoying this extra time with their kids and will miss it when it’s over.

Some people just got off their 12th double shift in a row at the hospital and can’t hug their family.

The whole piece is worth reading. It was written in March 2020 when we were all scared and trying to surf the waves of uncertainty. I think of the COVID articles I’ve read this is the one that has stayed with me the most.

Here in May 2021, there’s so much to look forward to: the vaccines are rolling out and we can see the light at the end of the tunnel. There’s a sense that post-pandemic we’re going to have a massive economic and lifestyle boom.

But today, things are still hard for most people. We need to continue to be empathic for the disparate ways in which the unyielding pressure of these years affects everyone, including ourselves.

Start Small

 ·  Permalink

I have a pattern I want to look out for and avoid.

When I have a habit I want to start, I bring the baggage of an expectation of what it would mean to do the final version of that habit. For instance, if I want to start running, I bring the expectation that a “proper run” is at least 30 minutes, or at least X fast, or at least 5 days per week. But, the critically important thing is just starting the habit. It’s way better to run for 3 minutes a day, slowly, twice a week than to push myself hard at the beginning, burn out, and never do it again.

I find myself doing this all the time. I can see the end goal of where I want to be, and I try to skip the steps that have to be done in order to build up to the full habit. This applies in fitness, in hobbies, and in programming.

James Clear writes about this in Atomic Habits:

“What matters is the rate at which you perform the behavior. You could do something twice in thirty days, or two hundred times. It’s the frequency that makes the difference. Your current habits have been internalized over the course of hundreds, if not thousands, of repetitions. New habits require the same level of frequency.”

Simply put, repetitions are more important than the size or quality of the habit. When I want to do something new, I’m going to start by designing the easiest version of that thing and then figure out where it can fit in my life and how I can make it a habit. Only then should I slowly ramp up to the bigger, better, more rewarding scale.

I was also reminded of the concept this week by discovering the Hybrid Calisthenics YouTube channel. In it, creator Hampton demonstrates a series of exercises that allow people to ramp up their fitness to be able to do push-ups or pull-ups, but he starts from the idea that you’re an absolute beginner with no inherent fitness. The videos are extremely refreshing in a world where fitness is often exclusionary.

Everyone needs to start somewhere and the best way to get to your end goal is often to cut yourself a break and start small.

OmniFocus 4 Beta

 ·  Permalink

Learn OmniFocus has a First Look at OmniFocus 4 coming on the heels of Omni announcing the beta.

TLDR: Switching to SwiftUI is allowing Omni to build new components for the iOS platforms that are much more akin to what we get on the Mac.

The iPad and iPhone versions of OmniFocus are great for quick entry or checking a list but I find they are not as easy to think in or work in as on the Mac.

The rapid editing of tasks and notes on display in OmniFocus 4 is a huge step in closing this gap. It also feels aligned with the design style of touch interfaces that have you directly manipulate your content without switching between modes.

I’m really impressed at Omni’s willingness bet on the modern Apple frameworks. SwiftUI still has very rough edges. It’s courageous for them to embrace it this early. That said, this looks like a great demo of the power of SwiftUI to raise the bar and provide consistent interfaces across all platforms.

Along the lines of being a better app to think in, my one wish list item for OmniFocus 4 is better note handing. Things does a better job of integrating notes fields into projects so that the source of truth about a project can stay in one app. At a minimum, I hope they at least make the font size in the notes field adjustable.

Smart Home Standards “Matter”

 ·  Permalink

We have some details on the new smart home alliance (now called Matter).

Stacey Higginbotham:

With Matter, consumers won’t have to research if their Nest cameras will work with their Schlage locks or if their HomeKit compatible sensors will also work with Alexa, for example. Developers won’t have to keep up with multiple ecosystems and integrations. Initially, this will only work across a limited number of devices, but those devices include lighting, blinds, HVAC, TVs, access controls, safety & security products, access points, smart home controllers, and bridges.

I’m half surprised it took this long for these companies to do this, and half surprised in this era of intense competition that this happened at all. Either way, it is a win for consumers. All the big players are involved (even Phillips Hue!)

That said, I bet it is still at least another few years before smart home technology goes truely mainstream, and I hope that before it does this alliance can put some more privacy protections in place. Companies selling cheap smart home tech on Amazon aren’t really motivated to invest in privacy without some external pressure.

Flushy the Toilet

 ·  Permalink

We woke up yesterday to find a whole bunch of water puddled in our kitchen. There’s a toilet in my son’s room above the kitchen, but my wife and I investigated and it didn’t seem like it was leaking. Nevertheless, she called an emergency plumber to come check it out.

The plumber got here and in five minutes was like, “there’s a huge puddle of water on the floor… the toilet has been leaking for a long time.” I guess we didn’t look with our eyes. We think that maybe we had a waste basket underneath the leak for a while and so we never noticed.

The toilet wasn’t fixable – it needed to be replaced. So the plumber replaced it. Took like an hour, problem solved.

However, we did not anticipate my five-year-old’s reaction to seeing the new toilet. There was immediate shock and sobbing. Over the course of two hours he went through all five stages of grief. There was denial that his old toilet was gone, anger at us having removed it, bargaining as he tried to convince us that we could get the old one back and we could have both, depression as he became resigned to the new reality, and finally, he named the new one Flushy.

“Flushy is the best toilet I ever had. Except my old potty. I’m going to name him Dunkie. I miss Dunkie.”

He’s planning on putting googly eyes on it.

I guess we should have seen this coming? Toilet attachment wasn’t in the parenting books. But it is the only toilet he has ever known. I think this was maybe his first real lesson in impermanence and the Four Noble Truths. You never know where life’s lessons will come from.

Goodbye, Nest

 ·  Permalink

The iPhone revolutionized more than just phones. When Tony Fadell first started taking about Nest, his startup that would take the battery and processor innovations from the iPhone and put it in something as boring as a thermostat, it was a revelation.

Nest had an incredible early run. With an extremely small team (less than 130 people) Fadell essentially created the smart home industry. The original Nest had Apple’s insane focus on out of the box experience, app design, and delight applied to a device that hadn’t changed in decades. It meaningfully improved user experience and the environment. Three years later, they made a smoke detector, again applying software, hardware, and policy design to reimagine a boring commodity device.

A year after that, Google bought Nest. Since then, there’s been this sense that Google doesn’t know what to do with it. There were internal drama and culture problems and Tony Fadell was pushed out (likely for good reasons).

Modern Google is trying very hard to invest in hardware, but Nest is now a brand and not a company, and it seems rudderless.

Personally, I’ve become wary of Google’s privacy practices. I use some Google products (Docs, Sheets, YouTube), but I’ve drawn a line in areas like email and search. Today, my Nest smoke alarm reached end of life. Instead of replacing it I realized that I’m uncomfortable having Google devices in my home. I’ve replaced my thermostat and smoke alarms with alternatives.

I appreciate the Nest that showed us it was possible to innovate products long since assumed to be done innovating. I hope a new generation of companies can take the mantle and run with it.

Lemur Dev Diary: Filtering Continued

 ·  Permalink

Lemur is a simple meal planning app in active development. I’m documenting some of the design, product, and development decisions as part of the Lemur Development Diary.

I’ve made some changes based on the discussion in the last post.

Current Design

I’m liking the distinction between main and sides. But, this introduces some new challenges:

  • I was having no problem categorizing things until I ran right into “Caesar Salad”. The salad can be a main or a side. And, of course, there are lots of dishes that operate that way. This isn’t boolean.
  • Restaurant is sort of weird here. Mains and sides have Difficulty, but restaurants don’t. It’s kind of like a difficulty of zero. Also, a restaurant isn’t a main or a side, it’s a place. The filtering might be fine to work as above (you pick a main, side, or an eatery) but the categorization is more complex.

I’m thinking of something like his when you make a dish:

Updated Design

I’ll need to mess around with the design here to make it not terrible, but I think the idea is sound. By default, most stuff is going to be a prepared meal with a main, so the defaults there are fine. For the most part, you probably just need to choose a difficulty and that’s it.

When it’s a restaurant, you hit that and you can opt out of all other options. When it’s prepared, something can be a main, a side, or both and it has difficulty.

Lemur Dev Diary: Filtering

 ·  Permalink

Lemur is a simple meal planning app in active development. I’m documenting some of the design, product, and development decisions as part of the Lemur Development Diary.

The basic structure of Lemur has two main areas.

This is the Plan:

And this is the List of Dishes:

Choosing a meal time displays a list where you can populate a meal with a dish that already exists or create a new one:

Lemur’s core mission is to make the flow of looking at your week (or a few days into the future) and populating the list with meals as quick and painless as possible. To make this efficient, I want to focus on the kind of thinking that happens when you’re trying to meal plan. I can present every dish in your database, but ideally, you’d have ways to look at things contextually. The current options on the screen to add a dish to a meal are:

  • Search
  • Sorting by Recent or Alphabetical
  • Filtering by Difficulty or Requirements

When you’re trying to decide what to have for dinner on a Tuesday, you’re trying to fill a specific slot:

When you do that, I have been thinking that you’d ask yourself two primary questions:

  1. What do I have the capacity to prepare? (Difficulty)
  2. Do I have the things I need to prepare this? (Requirements)

As a result, when you add a new dish, right now the options look like this:

After living with this for a few weeks, I think Difficulty is on the right track, but I think Requirements isn’t right.

For me, the difficulty does matter. On a Saturday night, I have more time and energy to prepare something that requires more work. But, my flow for meal planning generally involves making the plan and then grocery shopping for the things I need to execute on the plan. As a result, I rarely run into a case where I’m planning to not have the things I need. I don’t think the Groceries/Pantry distinction is useful.

That said, I think that Restaurant might be useful, but it’s useful in that it indicates that the overall difficulty is zero. You don’t need to prepare anything except to go out or order Uber Eats. I think this can be better represented by adding a difficulty level that is effectively zero effort, or, when you mark a dish as a restaurant it removes the difficulty measure entirely. It’s more of a binary thing: is this a restaurant/take-out option or are you making it? If you’re making it, how hard is it?

As a result, I’m going to get rid of Requirements entirely for right now. I might add something to categorize Restaurants.

But, with what I have right now, t’s still too difficult to get to what you need.

I could add Smart Sorting. I could take your past choices and use it to populate the list of dishes, prioritizing things you often have for dinner. But, this feels like a leaky abstraction to me, especially given how much I love having breakfast foods for dinner. I’m also a little concerned that this results in a list that’s hard to mentally process because the order is all over the place. Still, this might be worth trying.

There seems to be a main/sides distinction. There’s a case where you’re going through the planning flow multiple times for each mealtime. For dinner, you’re adding a main meal, and you’re adding a side. If you’re trying to find the main meal, it’s annoying to have “Green Beans” in the list of possible items. This also seems like it might be a leaky abstraction because some mains can be sides, and some sides can be mains. But, I won’t stop you from doing that — we’re just trying to help you whittle down to a sane list that you can process visually.

The current sorting on the meals page looks like this:

I’m thinking that from an importance perspective, sorting is less important than filtering in finding what you need. Right now sorting is prominent and filtering is hidden behind a tap. If we reverse that and we add some more categorization options, we’d end up with something like this:

This enables quick filtering between mains and sides, and it also supports finding restaurants if it’s the kind of night where you just can’t even.

For sorting, I think I want to support Alphabetical, Frequent, and Recent. But, I don’t think people will often change between those. There’s probably some upfront preferences that make sense. So, I think I’ll start by defaulting to Alphabetical and maybe providing this an option in settings, rather than on this screen.

I’ll try this out in the beta and see how it feels over the coming weeks.

Lemur Development Diary

 ·  Permalink

Some of my favourite programming writing is Brent Simmons’ Vesper Sync Diary. Brent does an amazing job of describing the challenges encountered while implementing sync: one of the hardest things in programming to do well. Sync is often talked about in the abstract, but Brent discusses the specific tradeoffs of various solutions in concrete examples for the late notes app Vesper. The sync diary made a huge difference to the way I think about programming and writing about programming. I’m going to experiment with doing something similar.

For the last four years, I’ve been working on a little app for doing meal planning. I call it Lemur. It has gone through several iterations as a stack of paper index cards, a web app, a React Native app, and finally a native iOS app.

I don’t really want to write an app to do meal planning. But, I’ve tried dozens of meal planning apps over many years and none of them are right for me. Meal planning is something I have struggled with for years, so I’m making this thing because I personally need it. As I go through my journey of discovering what works for me, I’ve changed the app to incorporate what I’ve learned. I think, however, that the app might help other people too, and so eventually I’d like to release it.

I’m doing this alone, so I’ve been treating my role like more of a movie director than a producer. I spend a lot of time thinking through the little details of what makes a simple app like this useful, delightful, and nice.

There’s a few basic principles I’m working with:

  • The core problem to solve is: how do you quickly, efficiently, and delightfully plan what a family is going to eat.
  • The app should be “nice”.
  • I’m not aiming to build an app that does everything related to meals. A lot of the existing apps do the whole kitchen sink or focus on integration between meal plans and grocery lists. I only care about acing the process of making a meal plan.
  • I’m not prescriptive. I’m not telling you what to eat. Everyone is on their own journey. Maybe one day suggestions might be a thing, but I doubt it.
  • It has to be a better experience than just writing things down on a paper sheet with a pen. If the app doesn’t have app-specific advantages, there’s no point.
  • Seamless sync is necessary. Meal planning for a single person is generally not that complex. If you add the requirements and preferences of a family, you need sync to make the app worth it over what you can do with a paper sheet.

As I get closer to putting this on the App Store for people to try, I’m going to be working though some design, development, and product challenges. The most interesting of these I’ll write about here. Here’s some examples of what’s coming:

  • I’m struggling with when and how to appropriately integrate images into the meal planning process. Adding images makes things look nice, but it impacts speed in a way that isn’t great. I’ll work through the pros/cons.
  • I’m also trying to figure out what kind of filtering or sorting is the most conducive to finding dish options for a given time. I’ve tried difficulty and capacity filtering, some of which is working and some of which is not. I’ll show you were I’m at for this and talk through some of the tradeoffs.

I’m looking forward to sharing this journey with you.

COVID via Aerosols

 ·  Permalink

From a compelling article by Professor of Chemisry Jose-Luis Jimenez on the argument that COVID is transmitted via aerosols:

The visual analogy of smoke can help guide our risk assessment and risk reduction strategies. One just has to imagine that others they encounter are all smoking, and the goal is to breathe as little smoke as possible.

When I’m in uncomfortably close proximity, I naturally hold my breath. It’s nice to know that’s not entirely insane.

I propose the following: Avoid Crowding, Indoors, low Ventilation, Close proximity, long Duration, Unmasked, Talking/singing/Yelling (“A CIViC DUTY”).

That’s a horribly difficult acronym to remember. But, the visual model of dealing with smoke drives home the required change in behaviour.

I’m happy that Ontario schools concentrated on ventilation and moving classes outside, even before the evidence was perfectly clear.

This model could turn out to be wrong, but the additional precautions don’t seem like a heavy burden against the potentially significant increase in safety.

Quickly Create Email Rules

 ·  Permalink

I’m trying to get better at setting up email rules. If you’re not going to use Hey or something like it, you have to do some work yourself to not be buried.

I recently discovered that both Fastmail (which I use for personal) and GMail (which I use for work) support a flow to quickly create a rule from an example email.

In Fastmail, this option is “Add Rule from Message” in the hamburger menu:

This then pre-fills the sender and the subject:

GMail has the same option as “Filter messages like these”.

If you get into the flow of doing this regularly, this can quickly help get recurring and annoying messages out of your inbox.

From Kindle to Bear

 ·  Permalink

I was looking for an easy way to import my Kindle highlights into Bear, as I’ve been using Bear as my knowledge management system (Zettelkasten). I want to be able to put my highlights in the same place as the notes for the books I read.

Two things made this really easy:

  1. Bookcision is this amazing bookmarklet that can take the Kindle highlights from Amazon’s highlights page (read.kindle.com) and dump it into a text file, or XML, or JSON so you can save it. This is good in case the Kindle site ever goes away, and it gives us a document we can work with. No matter where you’re putting your highlights, this is a good first start.

  2. If we’ve got a JSON file, Shortcuts.app is great at parsing JSON and also great at importing to Bear. I thought about writing a script for this, but to be honest it’s so fast to do this in Shortcuts that it’s not worth it.

Here’s what the Shortcut looks like:

Once you’ve got a JSON file, formatting it in Shortcuts is really quick and makes for quick entry into Bear.

The NYT Article About the Election Delay Tweet Could Be About My 4-year-old

 ·  Permalink

Reading this article I can’t help but think of a preschooler who desperately needs a time-out.

Mr. Trump is facing about as dire a run-up to a presidential election as any incumbent could imagine: the worst quarter in the economy on record, an unceasing health crisis, protests nationwide and a country paralyzed by the lack of a financial recovery plan with no solution in sight — all compounded by his own inability to curtail his behavior.

Sometimes 4-year-olds find curtailing their behaviour challenging.

Aides have described him as pained by the widespread rejection he is seeing in public opinion polls, even as he continues with self-sabotaging behavior rather than taking steps that might help him…

Well, at least he’s not testing boundaries:

Mr. Trump, who often tests the boundaries of his authority, has increasingly used public comments to lay groundwork for arguing that the election results are illegitimate if he loses.

Or, giving empty threats:

This is not the first time that Mr. Trump has raised the idea of thwarting rules or laws that he finds objectionable, and he often fails to follow through. He has repeatedly hurled threats, whether it is defunding universities or blocking federal aid to states, the substance of which he has no intent, or capacity, to fulfill.

Heads Up Display with OmniFocus

 ·  Permalink

I’ve been using OmniFocus for task management for at least a decade. In all that time, I’ve struggled with getting a key part of GTD right. The intention behind any task management system is that you put all your stuff in there so that at the exact moment you need it you find it. When it works, it’s the kind of magic that leads to having a truly “trusted system”.

I am diligent about putting items in the Inbox, tracking them, moving them into projects, setting defer dates, and reviewing regularly. But, until recently, I didn’t have a good answer for how I figure out what to work on next. Ideally, I’d have a view that shows me everything that’s “On Deck” and from that I can choose from the most important or the items I have the capacity to work on. But every time I tried to make something like this work with Custom Perspectives, I’d find myself falling back to going through all of my projects one-by-one hunting for things.

The magic of important items floating to the top just wasn’t happening. But after some experimentation, here’s what I’ve landed on. My primary perspective:

  • Shows me the critical projects. I start with projects within my “Work” folder or a handful of hand-selected projects that I know I want to see.
  • Only shows me stuff that’s marked as “Available”. I get a lot of use out of defer dates to keep things that I can’t act on out of my head. This is also an easy way to push something a few days or a few weeks forward if I know that I’m just not going to deal with it right now.
  • Shows me due soon or flagged. I want to see these no matter where they are in my system. I don’t want to feel like I might miss something, so anything with a due date coming up needs to be in my focus.
  • Only shows me projects that have actions in them. I want things that I can do something about right now. For projects that have no actions, I’m counting on regularly reviewing them in the Review perspective to make sure I’m moving forward on them. But, when I’m working, I’m in a different mode than trying to figure out how to break down a project.

Perspective Settings

This perspective has also taught me the value of something that I seem to have been missing for years of working with OmniFocus. Because I’m so used to going into each project hunting for actions, I’ve missed out on the ability that OmniFocus has to show you multiple projects at the same time. I don’t know how I’ve really devalued this so heavily.

I was looking at all of my projects individually, one at a time:

Individual Project View

But with OmniFocus, you can look at the and modify whole group!

Combined Project View

This means that if you get the perspective right, you end up with a heads up display of everything you need to accomplish. I’ve always thought that the way to get the benefits of working across projects was with tags, but this view coupled with the perspective above, is finally a good fit.

Small, Nimble, and Quick

 ·  Permalink

I’m a big fan of larger frameworks like Django or Rails or UIKit. I know there’s a bit of a war between the folks who like the out-of-the-box kitchen sink frameworks and those who want to mash together their own framework from a series of libraries. I find that most projects (even in the microservices world) approach a size and scale quickly that makes the larger frameworks worth it. Otherwise, I often end up reinventing stuff that has been done better by people way smarter than I am.

However, I recently got a reminder that sometimes small tools built from libraries can be elegant.

I just moved this blog from blog.benjohnson.ca to benjohnson.ca. And in the process, I need to properly handle HTTP redirections for SEO and to generally be a good web citizen. But, I host my blog at micro.blog, and they don’t have redirection logic built in. I figured it wouldn’t take long to spin up a small redirection service that I could host at the old domain to send traffic to the new one, and that Express might be the right fit.

It took 5 minutes and 9 lines of readable code:

const { URL } = require("url");
const express = require("express");

const app = express();

app.get("/*", (req, res) => {
  res.redirect(301, new URL(req.url, "https://benjohnson.ca"));


I’m sure I could solve this with a shorter Nginx config or do it with a bigger framework, but it’s hard to beat the simplicity of 9 lines of readable and understandable code that can be run with node index.js in a Dockerfile. I even took an extra few minutes to add tests.

JavaScript has never had a great kitchen-sink web framework (though some have tried). There’s a bazillion libraries on npm and most people in that community are in the Libraries Are Better™ camp. I tend to give the community side-eye for this attitude, but this small project has been a good reminder that, of course, everything in programming has tradeoffs.

Subscription Publishing

 ·  Permalink

As much as we’re all going to need to watch our subscription counts, I’m looking forward to the world of subscription publishing Ev describes here.

Anything that increases the quality of journalism is something to be excited about. The resurgence of the Washington Post after Bezos’ purchase is, I think, evidence for the power of what stable revenue can do for publishing. Technology isn’t a good replacement for a lot of talented and motivated reporters.

That said, I don’t think it’s likely that this does much to address media polarization. Maybe with better journalism we get more of the rational middle, but if I had to bet I’d put money on these content bundles and subscriptions coalescing around political extremes.

This also doesn’t do much to prevent the death of local news. Though, maybe at scale that is a problem technology can solve.

Ramp Up and Interruptions

 ·  Permalink

RescueTime suggests that peak programmer hours are on average between 2pm and 6pm. This aligns with my experience that we need a solid ramp up period before being productive developers.

Once programmers have gotten going, interruptions are incredibly destructive to the tune of at least 15 minutes to ramp back up depending on memory load.

The ramp up period is so important and the cost of interruptions are so high that it’s important to find ways to defend your uninterrupted time. Book periods of work on your calendar, put up Do Not Distrub signs, get out of the office, etc.

It’s also really important for managers to monitor and defend their report’s time. If your manager isn’t doing a good job with this, it’s a good idea to talk to them about ways that they could help.

Of course, the relevant comic.

Framework Feel and Mark Gurman’s Combined iOS/Mac User Experience

 ·  Permalink

There’s been a bunch of discussion about Mark Gurman’s article on Apple working on a single user experience for iOS and Mac apps. We’re not entirely sure what Apple intends here, which is leading to a lot of concerned speculation. One take (summarized well in John Gruber’s article on the subject) is that this will cause developers to port their iOS apps directly to the Mac, resulting in a mass influx of poorly designed Mac apps. “Write once, run everywhere” has never gone well.

I’d like to propose a possible middle ground suggested by React Native:

It’s worth noting that we’re not chasing “write once, run anywhere.” Different platforms have different looks, feels, and capabilities, and as such, we should still be developing discrete apps for each platform, but the same set of engineers should be able to build applications for whatever platform they choose, without needing to learn a fundamentally different set of technologies for each. We call this approach “learn once, write anywhere.”

React Native allows developers to write cross-platform iOS and Android apps, but it suggests that developers ship a different UI for each platform. It aims for parity of framework feel over parity of user interface. With a set of tools and frameworks that feel similar regardless of platform, developers can be productive and apps can easily share underlying code that is not exposed to the user interface (business logic, network code, etc.).

Maybe this is what Apple intends. Underlying framework parity (UIColor is UIColor) and a set of UI frameworks for the Mac that feel like developing with UIKit but don’t easily allow for a direct port. It might let them keep what’s great about the Mac but open up the field to more developers.