Justin Duke

Migrating from moment to date-fns

I got a lot of positive feedback from my recent article on how I cut my webpack bundle size in half, and a common refrain was how folks found themselves in the same position as I did in terms of deciding to migrate off of moment.js.

A handful of folks suggested date-fns as an alternative. date-fns has a relatively clumsy name but offered excatly what I was looking for:

  • Modularity and tree-shaking compatability.
  • Use of native dates
  • TypeScript support

So I decided to take the plunge and try migrating: the surface area of my use of moment wasn’t that large, so I hoped it would be relatively painless.

(Spoiler alert: it was.)

Read more →

A month with the AirPods

I bought them, you see, despite my better instincts.

I already had BlueTooth earphones that worked (albeit not well).

I already had a pair of Bose over-the-ears that are perfect for day-to-day work and for noisy situations, like planes and crowded coffeeshops.

And my army of EarPods (or, perhaps, EarPods knockoffs — I purchased five of them for like $50, with the understanding that I’d lose or break a pair every month or so) was still fine, though its ranks were slowly dwindling.

But I’d been seeing more and more AirPods in the wild, and decided to get a pair.

The good parts:

  • To get the most important thing out of the way first: it is such a marked experience improvement over Bluetooth headphones that I can never go back. It is magic. I pop the little tic-tacs into my ear, I hear a nice little “boop!” noise, and I’m connected. No futzing around with pairings or Bluetooth settings. Even switching from my iPhone to my iPad or MacBook (and vice-versa) is an order of magnitude easier than on BlueTooth.
  • The comfort and sound levels are pretty comparable with EarPods. If that’s good (like it is for me: when I’m listening to stuff on them it’s usually an audiobook/podcast, so fidelity isn’t a huge deal), then, well, good.
  • The case is really nice. There’s something so pleasantly polished about it, and it’s small enough that you can toss it in your jeans pocket or messenger bag and not think twice.

The bad parts:

  • They look dumb. Like, really dumb. Their continued (and strengthened) popularity has not assuaged this at all for me.
  • The battery life is determinedly subpar, especially compared to other bluetooth headphones I’ve used. I’ve drained the entire thing in the morning and then even if I remembered to charge the battery case, I have to go without using them for a chunk of time in order to charge them.
  • The things are incredibly tiny and if you are a clumsy or forgetful dude like me, you will drop and misplace them. It is legitimately a wonder that I still have my AirPods.
  • The lack of physical controls is annoying. Having to use my phone to skip forward a song 1 or toggle the volume is bad.

Anyway. The AirPods are the most performant, practical headphones I’ve ever used. They make it incredibly easy to jump from morning chores to working out at the gym to video chatting. They’re goofy as hell, but that (and the $150) is a price I’m willing to pay to not have to futz with Bluetooth.

  1. Okay, or to skip podcast ads. [return]

How I cut my Webpack bundle size in half

In the fall, a young man’s fancy lightly turns to thoughts of front-end performance.

When I initially built out Buttondown, I was focused on two aspects above all else:

  1. It being built quickly.
  2. It working reasonably well.

Notably excluded from that list is performance. Buttondown isn’t a slow app, but it is a heavy one: the bundle size while developing is measured in megabytes, and there’s a non-trivial loading time for first-time users.

Now that the core feature base has stabilized and nothing is particularly in an “on fire” state, I wanted to turn my eye towards maintenance work, and a big piece of that was seeing what I could do to shrink that bundle.

Read more →

Not The Keynote You're Looking For

I hate to be in the position of defending Apple evangelists, but there have been a lot of weird takes about the Apple leaks the past few days. Here’s one:

I think the comparison between Star Wars and Apple products is particularly apt because, well, Star Wars isn’t “commercial art”: it’s a meticulously managed piece of intellectual property. It isn’t a singular artistic vision: its the culmination of hundreds of stakeholders, producers, focus testers, and marketers. So much so that the director of a Star Wars movie just got replaced, like a poorly-performing engineering manager:

Lucasfilm and Colin Trevorrow have mutually chosen to part ways on Star Wars: Episode IX. Colin has been a wonderful collaborator throughout the development process but we have all come to the conclusion that our visions for the project differ. We wish Colin the best and will be sharing more information about the film soon.

The primary goal of a Star Wars movie is to entice audiences to engage more in the Star Wars universe: to create buzz, to purchase merchandise, to consume more Star Wars media. It accomplishes this by putting out an entertaining, easily consumable, but unchallenging product. (And, sure, sometimes it gets a little derivative.)

The primary goal of an Apple keynote is to entice the audience to engage more in the Apple universe: to create buzz, to purchase products, to consume more Apple media. It accomplishes this by putting out interesting (albeit comically self-indulgent) marketing material. (And sure, sometimes it gets a little derivative.)

I think it’s weird and unambiguously bad to complain that tech journalists are doing their jobs: of course they’re going to report on the leaks and of course they should report on the leaks.

I also think it’s weird to pretend that Apple fans are any different than Star Wars fans or Marvel fans or of any wildly successful franchise.

There are a lot of things to criticize about Apple, and even Apple fandom. But the act of just being excited about the new shiny things is, I think, harmless and honestly kind of lovely. There’s something so earnest about the idea of people being so excited to watch the keynote and see how their technology is going to evolve.

(For what it’s worth, I watch the Star Wars movies because I love big ol’ adventures, and I watch the Apple keynotes because I am a tremendous nerd. And I think complaining about spoilers is dumb.)


Turning 25

This week, I turned 25.

I spent my birthday doing the thing I want to spend every birthday doing: I reverse seared a filet, bought a nice scotch, and watched an old movie with Molly.

We were going to watch Bridge on the River Kwoi but didn’t want to start a three-hour movie at eight pm, so we watched The African Queen.

We have become so old. It is fantastic.

I do the thing I do every time I turn a new age, which is expressly deny the very concept of maturation until it seeps into my life anyway.

Like grabbing dinner and drinks with a couple friends who had moved out of town but were back for the week, and suddenly understanding that “grabbing dinner and drinks” has become an act that shifted from “order a pizza and go bar-hopping” to “make sandwiches and drink wine”.

(I mean, I still eat pizza, and we still go to bars. But we eat less pizza, and spend less time in bars, and besides on the week of your birthday you’re forced to wonder how things have changed.)

I am re-reading what I wrote this time last year, and discovering that most of my thoughts are redundant. I feel more mature but no more wiser. I feel like I’m getting more rest but am slightly worried about forgetting what it feels like to be restless.

I am waking up early (I referred to waking up at 7 as sleeping in); I am eating well. I find myself so tired at the day, but it’s an earned fatigue (to steal a friend’s phrase.). I am reading and writing and learning French, conjugated word by conjugated word. I can deadlift more than I could deadlift twelve months ago. I beat Persona 5.

And I’m happy. Really, really happy. If there’s something that I’m unhappy about, it’s that the days are short and the weeks are short and the months are the shortest of all.

We’re going to DC in a few weeks, and then after that Paris, and then after that we need to plan our next trip — Tokyo, maybe, or Edinburgh or Prague. And then after that, maybe Little Rock. I have always wanted to visit Little Rock, for reasons unexplainable.

There is still so much to discover.


Creating a password validator component in Vue

Sometimes you procrastinate one feature by writing another. Even if that other feature is pretty small and inconsequential. 1

For me, that other feature — if you can even call it a feature — was password strength testing for Buttondown.

Read more →

Side Projects: July 2017


  1. Buttondown continues to grow, as does Spoonbill.
  2. Consolidated my web stuff. This site is better than ever, Village Blacksmith is nice and clean.
  3. Still launching dope stuff on Buttondown: I’m particularly proud of its new embed support, which will hopefully integrate with Medium somewhat soon.


  1. Buttondown continues to be unprofitable, as does Spoonbill.
  2. I didn’t launch Very Cute, though I got a bit more progress on it. (I don’t feel that bad about this, because it was a productive month — it’s just that most of my cycles were poured into Buttondown.)

What’s Next

  1. Going to retool Buttondown’s pricing to try and monetize the majority of the user segments who don’t qualify for the current pricing schema. For $19/mo, you can set a custom redirect URL, remove branding, and probably a couple other things.
  2. Sticking to that. I think with the current amount of energy I’m spending on Buttondown it’s prohibitively difficult to work on something else. (More about this later.). There are a couple projects I want to do (React Native version of https://coinmarketcap.com/, public Airtable tracking SaaS prices, simple AWS infoproduct…) but I don’t think I can commit to any of them right now.

Other Thoughts

  • The past couple weeks have been exhausting! My schedule has felt packed to the gills: wake up early, do chores and administrative stuff til 9, then work til 1, then work out, then work until 5 or 6. At that point I’m exhausted and have to choose between working on side projects or doing something fun and active. I’m been choosing the latter as much as possible — which is the right choice — but it means I don’t move the needle as much as I’d like, which means I feel guilty.
  • I’m really tempted to start tracking vanity metrics more, because they’re doing really well. But vanity metrics won’t buy me scotch.

Read more →

Creating a reusable tabbed card component in Vue

I built a thing for Buttondown that lets you embed an iFrame to handle subscriptions really nicely:

Read more →

There are still dragons everywhere

I’ve been programming for the better part of a decade, and I’ve been programming in Python for the better part of that better part.

As loathe as I am to assume the mantel of “X Engineer”, if I were to describe my career in relation to any technology it would be “Python Engineer”.

It is the language I feel most comfortable with; it is the language I reach to first when starting a new project; it is the language I write daily. It is as frictionless as English.

And yet I still find myself losing hours to things I thought I had mastered.

The other night, I played with the idea of bumping Buttondown to Python 3.6 from 3.5 — I wanted cooler types and faster dictionaries, and it seemed like a painless process, so I ran brew upgrade python and was off to the races.

Except something broke: there was an issue with how I was using grequests that was fine in 3.5 but not 3.6, and I decided to revert.

So I hit up pyenv to try and grab 3.5 (since it was no longer the latest thing installed on my machine) and use that to recreate my virtualenv.

Except now psycopg2 was broken for some reason?

It kept on throwing a bizarre error that had like, three matches on Google total:

ImportError: datetime initialization failed

So, I do what I’ve learned to do: nuke everything and start over.

Except now virtualenv is broken, looking for a global python installation that doesn’t exist: no such file or directory, it snaps back at me.

After a few hours of fruitless Googling and tinkering, I do the thing I’m not supposed to do: I just re-install the old version of Python with brew:

brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/ec545d45d4512ace3570782283df4ecda6bb0044/Formula/python3.rb

And suddenly everything works. I recreate the virtualenv; I reinstall the dependencies; I get back to work.

There’s no big lesson here. I probably should have stuck with 3.6 and figured out the grequests issue; I probably should have been more disciplined with installing 3.6 through pyenv and managing my environments.

But I think it feels good to get lost in a sea of arcana and development hell for an afternoon. I mean, it sucks in the moment — there’s no denying that. But once the moment passes, you’re reminded about how much left there is to learn and to master.


App sizes are under control, they just aren't under scrutiny

I wrote at the first of last month about bloat in apps, in response to a thoughtful piece by Ben Sandofsky about how he minimized bloat in Halide.

I had some misgivings with the post and the ideas it espoused — namely, that “bloat is bad” is a reductionist truism — but still admired the approach Sandofsky took and the clear tradeoffs and sacrifices he discussed.

This post by Trevor Elkins making the rounds today has the same message, though it lacks the nuance and pragmatism:

As app developers, we should be more conscious of the space we use. Take some time to remove the cruft that builds up and push back against needless waste.

So really, how does an app that occasionally sends me a connection request and recruiter spam take up 275MB? Maybe I’ll do an analysis at some point, but for now it’s deleted.

Trevor works for Kayak, whose iOS app weighs in at 176 MB.

Perhaps Trevor is actively working on reducing the size of the app bundle, in which case he knows how difficult it is to make decisions like do we spend two weeks reimplementing this framework or just eat the 5MB it adds to our final app size?

Or perhaps he isn’t, but he’s talked with fellow Kayak engineers who have determined that the bloat is worth the cost — maybe they’ve got a lot of high-resolution assets, or have decided that the development velocity a framework-heavy approach enables is worth the drop-off in installs.

Or perhaps he didn’t even know Kayak’s app size is so large in the first place, because it’s a factor that doesn’t impact the majority of users after the initial download. 1

Either way, it’s kinda shitty to insiniuate that an app is bloated due to incompetence; it’s kinda shitty to insiniuate that an app is bloated due to indifference.

Everything is a trade-off. Some companies don’t think it’s worth it to slim down their bundle sizes; some companies do. It’s disingenuous to pretend otherwise.

(For what it’s worth, I think the Kayak iOS app is great.)

  1. Which isn’t to say that it doesn’t impact users — it’s to say that the surface area of the impact is pretty small. [return]
© 2017 Justin Duke • All rights reserved • I hope you have a nice day.