Oh hi, I didn't see you there!

Welcome to DevChat #8! Here's what's on deck:

  • Inbox zero sleepy times
  • Tricksy email previews
  • JavaScript functions have length
  • Yeasty popcorn cats

This is an archive of a DevChat newsletter. To get the next one early, and in your inbox, sign up! To read past issues, head to the archives!

Inbox zero sleepy times

Long ago I read the book "Getting Things Done" by David Allen. It was already showing its age at the time, but still lit the original fire under me for paying attention to process and to removing mental overhead. Around the same time I also read a lot of LifeHacker and related sites, plus a myriad of books on the topic of how to crush your work without being crushed in turn.

After a decade of reading about and trying all kinds of processes, with a huge range of complexity, I can boil it all down into a few core wisnugs (Nuggets of Wisdom):

  1. If there is something you need to remember, put it into a searchable system that will automatically remind you at a useful time. Even if you have a brain that allows you to keep track of such things reliably, having to do so creates mental overhead for everything else you're doing. This is related to the DevOps principle of Making the Work Visible.
  2. Your work-visibility/reminder system must be as slick, simple, and accessible as possible, or you will stop using it.
  3. When dealing with a piece of work, the first question should always be, "Can I not?" If you can punt it to later, there's a pretty good chance you can not do it at all. Most things that seem important aren't. Purge ruthlessly.
  4. When a piece of work becomes visible, either deal with it immediately or put it back into your reminder system. The more times that work pops back up in your reminder system the stronger your preference should be for dealing with it immediately. But you should always prefer dealing with it immediately anyway, otherwise your list of reminders will grow forever.

There is an incredibly simple combination of an idea plus a tool that enables this:

  • The Inbox Zero philosophy
  • Snooze buttons

While "Inbox Zero" is often thought of with respect to email, it's a general-purpose concept. It goes like this:

Inbox Zero: Something that requires a decision about if and when to do it goes into an "Inbox" (could be an email inbox, could be a column in a Kanban board, could be a default tag in GitHub Issues, etc). You, as the keeper of the Inbox, have a schedule by which you visit the Inbox (you can always visit less often than you think, but frequency depends on what kinds of stuff goes in there and how urgent it can be). When you have left the Inbox, there will be nothing in it. You will have deleted everything you could delete, performed every related work item you could reasonably perform, and converted everything else into next-step actions dumped into a system that will ensure those actions are taken.

During this process you will have created a bunch of future work. This is where Inbox Zero always falls apart because that future work has to get done by the right person and at the right time. Systems to manage this can get quite complicated.

This is where the noble snooze button (or equivalent) comes in. When you decide something needs to be done later:

  1. Acknowledge the reality that work is unpredictable and you don't truly know when it will get done.
  2. Pick a reasonable date upon which you can re-evaluate the work to decide if it is time, and there is time, to do it.
  3. Snooze that work item so that it automatically reappears in your Inbox on that date.

Here's what this looks like for me, with my work email Inbox. I check my email a few times a day. (If I'm being honest, this is more than is necessary. Just doing so in the morning would be sufficient.) For each email:

  • If the subject line looks like someone trying to sell me something, I delete it without a second thought (I assume GDC sold my info to infinity game-related companies...).
  • If the email creates a minor task for me to do, I perform it right then and archive the message.
  • If it creates a less minor task:
    • If that task is email-related (e.g. replying to the sender) I snooze it in Gmail until a date when I want to re-evaluate. I do this most often with things I need to follow up on, e.g. when someone says they'll get a signed contract over to me or something. I also do this when I know I need to compose a thoughtful reply but don't have the time/energy at the moment.
    • If that task will not result in sending a reply, I convert it into a card in the Inbox of our work management system (ClickUp) and archive the message.

The end result is that the only things in my email are things I haven't seen yet, or things that I had previously decided to revisit later. This only works if that latter type is not allowed to grow faster than it shrinks!

And here's what it looks like for our team, with our work management system (ClickUp):

  • Every Monday we have a Production Meeting wherein we agree on studio priorities for the week, identify resource bottlenecks, and sort out project priorities for each person on the team.
  • Any new work, created from any source at all, goes into the Inbox (where "Inbox" is a "status", equivalent to a Kanban/Trello column). The card includes all relevant information and assigned parties.
  • Every morning, we pair up in "Accelerators" to review the prior day's work and clear the Inbox. (Here we're just focusing on the latter.)
  • For each item in the Inbox, we judge the importance against the studio and personal priorities established in the Production Meeting. If the Item aligns with those priorities, or triggers a change in priorities, it gets put into the very short list of on-deck tasks for the week.
  • Most Inbox items can be immediately deleted, since most work does not need to happen.
  • Those that remain are not a priority of the week, and we can't know when they'll be a priority. So we add a "due date" (which we interpret to mean "re-evaluate date") and dump it into the ever-growing ToDo pile (another status/column).
  • We never look at the ToDo tasks.
  • We have an automation that moves tasks from ToDo to Inbox on their due date.
  • Rinse. Repeat. Recycle.

This system is incredibly simple, which is the main reason it is so effective. No one has to mentally keep track of what has to happen later, and we don't have to pretend we can predict the future. Still, it only works if the list of snoozed items doesn't grow without bound. And the only way to prevent that is to be realistic about what will and will not get done.

There is a nuance here. What "will and will not get done" is not quite the same as "what is and is not important."

Most work eventually gets deleted, because as time goes on and an item gets repeatedly re-evaluated and punted, it becomes increasingly likely that it simply won't get done. Even if that thing is obviously important. There is always more "important" stuff to do than there is time to do it all. The only way to manage this problem is to delete every task you can get away with deleting. If you can get away with not doing it, then it's less important than something else you should be doing instead.

Do you have your only Getting-Things-Done and Inbox Zero wisnugs? Share them!

Tricksy email previews

Depending on your email client, when looking at a list of messages you probably see three things:

  1. The sender's name.
  2. The subject line.
  3. A preview of the contents (e.g. the first sentence of the body).

You may have noticed that sometimes that preview doesn't actually appear anywhere in the actual content. Where does this sneaky and false preview come from?

I noticed this back when I was building our newsletter system (the very one that sent you this message), as I was studying how other services implemented mass mailing, templating systems, and so on. These services typically include a field for the message creator to populate this preview. Maybe they call it a "snippet", or a "preview", or a "blurb", or something else entirely. The point is, they let you choose what recipients will see as the preview. But how does it work?

Turns out it's pretty simple. Most of the emails we get are HTML (instead of plain text). Most email clients understand HTML perfectly fine, and also allow for some basic CSS (the thing that controls how web pages look). Email clients are frustratingly behind the times when it comes to CSS, so your presentation options are quite limited, but they have more than enough to solve the problem at hand: the magical mystery preview.

All that happens is that the "preview" text is added to the email as the first content in the HTML, but with a combination of CSS properties that makes it highly likely to not be shown even by email clients that can barely handle CSS at all. It'll look something like this:

<span style="display:none;font-size:1px;color:#333333;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;">
  Sneaky, magical preview text!

The parser that decides what the "first line" of the body is in order to display the preview to you ignores CSS, but the parser that displays the whole email to you does not. And there you have it, magical email previews!

But we can take that one step further. The Substack service is all the rage right, and last week I noticed that a newsletter I'd signed up for not only included that magic preview but also the preview only included the preview text. The prior trick is great for controlling the first thing that someone sees in the preview, but if your preview text isn't long enough to cover the width of the preview render space, then the rendering will grab even more text (probably the first actually-visible sentence of your email body). Substack had a neat trick for this -- they add a whole bunch of whitespace characters to the end of your snippet text:

<span style="display:none;font-size:1px;color:#333333;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;">
  Sneaky, magical preview text!
  &nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj; <!-- many MANY times -->

You may be wondering why that whitespace isn't just trimmed away by the renderer. Apparently that's what that &zwnj; ("zero-width non-joiner") character is all about. I had never heard of the thing, but apparently its existence prevents the stripping of that whitespace. The end result is that your preview text has a ton of non-stripped whitespace after it, so that the likelihood of someone being on a monitor wide enough to show your text, plus all that whitespace, plus the next line of content-text is extremely low.

Do you know of any other newsletter-rendering tricks? I'd love to hear about them.

JavaScript functions have length

Look at this:

function myFunction (firstArg, secondArg){ /* do some stuff... */}
console.log(myFunction.length); // prints `2`

Weird, right?

I discovered this while working with Shi on our new test library for GameMaker Studio. We were using the JavaScript test library Mocha for inspiration, and there was something I couldn't figure out:

// In Mocha, test functions are registered via the `it()` function

it("can do something synchronously", function(){ /* plain old synchronous code */})
it("can do something asynchronously", function(done){ /* something that eventually calls `done()` */})

Since the same registration function (it()) is used for both async and sync tests, how did Mocha know whether the test function I provided was async? It would have to be able to analyze the call signature of the function!

It turns out there are a few ways to do that in JavaScript, but the only dependable one is the .length property. In JavaScript, functions are objects, and the .length property of function objects is the tally of how many arguments the function definition includes. So all Mocha would have to do is check if the function's length was 0 (synchronous) or 1 (asynchronous)!

This is all neat, but unfortunately also revealed that we couldn't do a similar trick in GameMaker since there is no way to get call signature information about functions in that language. That meant we had to instead use registration functions that would tell the library which kind of function we were supplying (e.g. it() and it_asynchronously()).

Have you found any other use cases for JavaScript function .length? Share!

Yeasty Popcorn Cats

Ori the cat wearing a storm trooper anxiety vest.

I only recently discovered the magical substance called "Nutritional Yeast." It is what it sounds like: yeast that you eat (versus that you use for fermentation).

We originally bought some on a whim and then just sorta had it sitting in a cupboard for months. One night I was making popcorn and suddenly remembered we had it. I looked at it, then back at the popcorn, then back at the yeast... Why not? I threw a bunch in. After brief uncertainty due to the newness, I liked the umami and cheesiness it added immensely. Now I don't make popcorn without it.

This primed us for the second discovery: our cats love nutritional yeast. We randomly saw mention on the web of cats being into it, already had it on hand, and so gave it a try. It's now our go-to trick for dealing with food pickiness issues.

One of our cats has such extreme anxiety that he has to be on Prozac, and we had spent every damn morning for months trying to get him dosed. We finally got to a reliable solution by making something tasty enough that he can't resist. It works like this:

  • Open up a capsule, pour the powder into a small dish.
  • Squirt some fish oil in (this is good for cats anyway) and mix it up. The oil supposedly makes the bitter drugs harder to taste.
  • Add a Catit chicken & liver treat (this is the most powerfully high-value treat our cats are into) and some water. Thoroughly mix.
  • Mix in Fortiflora (supposedly helps with gut issues, which he also has, and the second ingredient is nutritional yeast!).
  • Mix in some nutritional yeast.

Okay, yeah, that sounds like a lot of steps, doesn't it? BUT IT WORKS. And the end result is basically a magical health elixir, so I guess this cat will now also live forever.

Have any pro tips of your own for powerful cat treats and/or medicating the little rascals? I'm all ears.

Next time

That wraps DevChat #8!

I've been having a great time hearing from readers. If you haven't said hello, please do!

Share with others by forwarding, or link directly to the archived post.

Have a great week!

❤ Adam