skip to content
A logo Linell asked a nice AI to create. Linell Bonnette

Writing the Code that Powers Your Code

On the craft and responsibility of writing code that shapes thousands of other developers' projects.

In a few weeks or so, the plan is to publish the v4 of Inngest’s TypeScript SDK. I’ve spent weeks thinking through the changes and I’m honestly a little terrified to ship those decisions. Not because they’re bad or wrong — a lot of thought went into ensuring the opposite, actually — but because they’re real. They don’t stay in my codebase. Once we hit release it’s going to ripple out into thousands of other people’s projects. I love writing code. I think a good, clean implementation is an art form all on its own and it only gets better when you glue a few of them together to make something really neat. I’ve spent my whole career trying to get better at the craft.

Relatively early in my career I was working on an application that required me to become pretty familiar with the Twilio SDK, to the point that I was digging into their internals often enough to care about their code because of how it affected my own. I forget exactly what I was doing, but it was something to the tune of grabbing call recordings and trying to chunk them into smaller files for speech-to-text. I’d been working on what felt like a simple problem for what feels like days in my hazy memory and, lo and behold, by doing some sleuthing in their codebase I was able to figure out what their code was doing that was causing the issues I was having and, using that information, I was able to figure out what I needed to do on my side to get my project back on track. It’s actually kind of neat that I don’t even really remember the specifics — I don’t remember whether I liked their decision or not at all. Because the code was open source I had a little window into another person’s art and the decisions they’d made, probably thoughtfully and with tradeoffs and considerations I would never know about. Their choice had a direct impact on my work, though. My code, my mental model of what was happening, changed because of their choice.

I thought about that moment more than it probably deserved. I couldn’t really articulate why it mattered until I started working in earnest on Inngest’s SDK and realized that I was now on the other side.

The past month or so has been spent ideating on and then working through changes to the Inngest TypeScript SDK, with the goal of bringing it from v3 to v4 in a way that improves our codebase based on things we’ve learned. It’s been positively a blast to think through all of the implications of potentially minor changes, the infinite ways developers may use and abuse the SDK we create, and all of the different things that go into providing a clean, clear, consistent user experience when they’re interacting with our system. I’ve spent years producing APIs consumed by others, but an API just produces output. As long as that’s happening, who cares, right? An SDK on the other hand *shapes codebases*. My code is your code. I’m not just throwing something over the wall for users — we’re effectively collaborating on code across time and space. Four years from now somebody could be stuck on an old version because of a lame, bad, stupid decision that*I made after tons of thought*. Every single line I write is echoed through thousands of projects that I’ll never see or use.

It is, of course, the same stuff I’ve cared about the whole time. It just feels like it matters so much more because my choices aren’t constrained to my codebase, my team, or even my company. My choices affect every single developer who has to interact with our SDK. It’s a bit of a power trip to know that when I hit publish on v4, anyone pointing at latest is likely to start experiencing issues due to breaking changes. It’s scary as hell though because what if my changes are lame? As I write this, I’m working on a small change that captures the whole dynamic. In v3, defining an invoke-only function required an awkward empty array:

inngest.createFunction({ id: "helper" }, [], async ({ step }) => { ... });

In v4, you just omit triggers:

inngest.createFunction({ id: "helper" }, async ({ step }) => { ... });

That’s it. But making it work — keeping everything well-typed whether you pass no trigger, one trigger, or an array—meant writing code that exists solely so users never have to think about it. Gnashing of teeth so their art stays pretty. Hopefully they just write the code that feels obvious and it works.

Thinking of my day to day work with this mindset is a little daunting, but so fun. I know that every time someone imports this code, a little bit of my art becomes part of theirs. I’m imagining that somewhere, someday, a developer is going to be stuck on something and they’ll end up deep in our SDK internals, trying to understand why I’ve made such a boneheaded choice. I hope they can tell that I was thinking about them when they see it.