Ben Johnson · About Lemur Archive
  • Lemur Dev Diary: Filtering Continued

    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.

    Oct 12 @ 10:42 AM  ·  longform & lemur
  • Lemur Dev Diary: Filtering

    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.

    Oct 9 @ 4:55 PM  ·  longform & lemur
  • Lemur Development Diary

    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.

    Oct 7 @ 6:34 PM  ·  longform & lemur
  • COVID via Aerosols

    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.

    Oct 3 @ 3:12 PM  ·  longform
  • Quickly Create Email Rules

    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.

    Oct 2 @ 5:26 PM  ·  longform
  • From Kindle to Bear

    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.

    Sep 15 @ 6:36 PM  ·  longform
  • The NYT Article About the Election Delay Tweet Could Be About My 4-year-old

    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.

    Jul 30 @ 8:00 PM  ·  longform
  • Heads Up Display with OmniFocus

    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.

    May 21 @ 4:52 PM  ·  longform
  • Small, Nimble, and Quick

    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"));
    });
    
    app.listen(process.env.PORT);
    

    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.

    May 19 @ 6:58 PM  ·  longform
  • Subscription Publishing

    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.

    Apr 4 @ 6:20 PM  ·  longform
  • Ramp Up and Interruptions

    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.

    Jan 7 @ 12:52 PM  ·  longform
  • Framework Feel and Mark Gurman’s Combined iOS/Mac User Experience

    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.

    Dec 23 @ 8:57 PM  ·  longform
  • Twitter
  • Micro.blog
  • RSS: All
  • RSS: Long Only