Latest Posts (18 found)
Justin Duke 5 days ago

Adding imports to the Django shell

I was excited to finally remove from my file when 5.2 dropped because they added support for automatic model import. However, I found myself missing one other little escape hatch that exposed, which was the ability to import other arbitrary modules into the namespace. Django explains how to do bring in modules without a namespace , but I wanted to be able to inoculate my shell, since most of my modules follow a similar structure (exposing a single function). It took the bare minimum of sleuthing to figure out how to hack this in for myself, and now here I am to share that sleuthing with you. Behold, a code snippet that is hopefully self-explanatory:

0 views
Justin Duke 1 weeks ago

September, 2025

The last of summer's grip finally loosened its hold this September, and Richmond began its annual transformation into something gentler and more contemplative. This morning's walk with Telly required a dusting-off of the closet-buried Patagonia puffer jacket; it's perfect for walks with Lucy, who has graduated into the Big Kid stroller making it easier than ever for her to point at every dog ("dah!"), every bird (also "dah!"), every passing leaf that dared to flutter in her line of sight. As you will read below, the big corporate milestone for me this month was sponsoring Djangocon and having our first offsite over the course of a single week. Sadly, our Seattle trip was once again canceled. Haley and Lucy both got a little sick, and we had to abandon course. It's weird to think this will be the first year since 2011 that we have not stepped foot in the Pacific Northwest. More than anything though, I learned this month for the first time how impossibly difficult it is to be away from your daughter for six days. It is something I hope I have to go through again for a very long time.

1 views
Justin Duke 2 weeks ago

Hidden coupons

Much of our work at Buttondown revolves around resolving amorphous bits of state and cleaning it up to our ends, particularly state from exogenous sources. This manifests itself in a lot of ways: SMTP error codes, importing archives, et cetera. But one particularly pernicious way is straight. An author can come to ButtonDown having already set up a Stripe account, whether for some ad hoc use case or because they were using a separate paid subscriptions platform such as Substack or Ghost that also interfaces with Stripe. And one of the first things we do is slurp up all that data so we understand exactly what their prior history is, how many paid subscribers they have, et cetera. As you might imagine, this is very, very effective because the biggest perceived barrier for users is friction and how difficult it is for them to move from one place to another. And every time we can make it incrementally easier for them, it's worth our while. However, as you can also imagine, we deal with a lot of edge cases and idiosyncratic bits of behavior from Stripe. (And if anyone from Stripe is reading this essay, please don't interpret it as that large of a complaint because Connect is a pretty impressive bit of engineering, janky as it is.) One thing we have to do is pull in all coupon and discount data. So this is for a variety of reasons that are all uninteresting. The point of this essay is to talk about a divergence and where the abstract breaks down. You might think, as we once did, that the way to do this is pretty simple. You compile a list of all the available coupons, and then you iterate through every single subscription looking for said coupons. This is also the approach outlined in the docs and surfaced in the dashboard, so your naivete is excusable. However, this neglects to highlight an entirely different genre of discount, which is ad hoc discounts that are created and applied during the checkout session process, as well as probably a couple other places in which I'm unaware. To iterate through these, you must iterate through the subscriptions themselves: I'm sure there are a lot of interesting and nuanced reasons why these intangible coupons are not actually available through the core endpoint — I also don't care! It is a bad abstraction that I can get two different answers for "what are the coupons for this account?"; it is particularly bad because the "real" answer is by looking in the non-obvious place. At the same time, I am sympathetic. "I should not have to create a dedicated Coupon object just to apply a single discount to a single subscription" is a very reasonable papercut that I understand Stripe's desire to solve; in so doing, they created a different (and perhaps more esoteric) problem. This is why API design is a fun and interesting problem.

0 views
Justin Duke 3 weeks ago

Weeknotes 2.0

Once upon a time, I wrote weeknotes for Buttondown. I’ve started them up again—the first edition is linked below. I’ll spare you the navel-gazing about whether they belong there or on the blog (I cover that in the other post). In short: this won’t really affect the blog. Most of what will go into weeknotes are things I’ve been too much of a coward to blog about until now

0 views
Justin Duke 3 weeks ago

Pulumi

I'm spending a lot more time lately using Pulumi. This is for a handful of reasons. The two biggest ones are as follows. First, we're ramping up our investment in quote-unquote infrastructure. We're sending a lot from our own machines and want to be able to scale that up in a way that is more observable, predictable, and legible. Second, external infrastructure is often a dark forest

0 views
Justin Duke 4 weeks ago

Another reason our pytest suite is slow

I wrote two days ago about how our pytest suite was slow, and how we could speed it up by blessing a suite-wide fixture that was scoped to . This was true. But, like a one-year-old with a hammer, I found myself so gratified by the act of swinging that I found myself also trying to pinpoint another performance issue: why does it take so long to run a single smoke test

0 views
Justin Duke 1 months ago

Why our pytest suite is slow

The speed of Buttondown's pytest suite (which I've written about here , here , and here ) is a bit of a scissor for my friends and colleagues: depending on who you ask, it is (at around three minutes when parallelized on Blacksmith) either quite fast given its robustness or unfathomably slow

0 views
Justin Duke 1 months ago

63 postcards

We have wrapped up the formal portion of DjangoCon. DjangoCon is not Buttondown's first conference that we've sponsored, but it is the first one that we've actually manned a booth at — and we did so in a fashion that I would describe as idiosyncratic, ramshackle, and informed by a charming bootstrapper ethos — which is to say, deeply on brand

0 views
Justin Duke 1 months ago

Django forever

Tomorrow, I am taking a very early morning flight to Chicago to attend DjangoCon US. Buttondown is sponsoring, less as an exercise in lead generation and more as an act of circuitous open source sponsorship, and perhaps "sponsorship" is not quite the right word compared to gratuity in the most literal sense

0 views
Justin Duke 1 months ago

Onboarding survey, one week in

One extremely compelling form of blogging, both for the reader and the writer, is the admission of defeat. Seriously: whenever you find yourself faced with an empty iA Writer window and a dearth of ideas, ask yourself "what have I been wrong about this week. " and let the digital ink flow

0 views
Justin Duke 1 months ago

Goodwill

One of the amazing things about Morrowind is that it's a combat-rich game in which you can feasibly go through much of the game without ever fighting; indeed, gaming up your Disposition with every NPC you meet is a key to a much easier and interesting experience. A major vendor that I rely on has had three major incidents this week

0 views
Justin Duke 1 months ago

August, 2025

The summer heat in Richmond clung to everything this August like a second skin, broken only by afternoon thunderstorms that sent Telemachus scurrying to his fortress of solitude (the upstairs bathroom), and Antibes — Lucy's first European stamps in her passport, her delight at the Mediterranean blue

0 views
Justin Duke 1 months ago

What follows GitHub?

It seems fairly clear that, as far as product lifecycle goes, GitHub is in its “Azure metered billing” stage. I don’t mean this as a negative value judgment in of itself — who am I to argue that GHE is not, from a certain utilitarian point of you, more valuable to the world than all of the things I’m about to kvetch about

0 views
Justin Duke 1 months ago

Ashland, 2025

Trundle is not quite the right word. When I hear trundle , I think of layers, of wool and dampness, of hitting the road before the sun does, wrapped in a blanket and uncaffeinated haze

0 views
Justin Duke 1 months ago

Three apps that will not change your life

After what has felt like a long winter of habitual reliance on my existing tools, I’m finally playing around with some new ones. This is a healthy habit—so long as you don’t convince yourself that you’re just one more App Store download away from a previously unimaginable level of personal satisfaction and joy

0 views
Justin Duke 2 months ago

July, 2025

Telemachus turned five, two weeks ago. He did not have a great July; Richmond's been roiled by storms (ten nights in the past two weeks have ended with him hiding in the bathroom before bravely emerging at two in the morning, having wisely assessed that the threat has passed); add to that the firewo

0 views
Justin Duke 2 months ago

Have you at least tried asking?

My wife got sick this past weekend, and as a result we had to cancel or at least postpone a trip to Seattle that we had been looking forward to. She's feeling much better now, and I am left with the task of recouping what I can from our reservations — a task much more satisfying and much less stressful than force-feeding her electrolytes and naan

0 views
Justin Duke 2 months ago

Bodies Bodies Bodies

More than anything else, Bodies Bodies Bodies is a perfectly reasonable and delightful way to spend 90 minutes. It is beautiful, well-acted, and consistently funny, with a banger soundtrack and a propulsive pace

0 views