Full Width [alt+shift+f] Shortcuts [alt+shift+k]
Sign Up [alt+shift+s] Log In [alt+shift+l]
51

Summarizing our recommendations for software documentation

from ntietz.com blog - technically a blog [alt+shift+b] in programming

Last year, my coworker Suzanne and I got a case study accepted into an ethnography conference! She's an anthropologist by training, and I'm a software engineer. How'd we wind up there? The short version is I asked her what I thought was an interesting question, and she thought it was an interesting question, and we wound up doing research. We have a lot more to go on the original question—we're studying the relationship between the values we hold as engineers and our documentation practices—and this case study is the first step in that direction. The title of the case study is a mouthful: "Foundations of Practice: An Ethnographic Exploration of Software Documentation and its Cultural Implications for an Agile Startup". I mean, it's intended for a more academic audience, and in a field that's not software engineering. But what we studied is relevant for software engineers, so let's talk about it here in more familiar language! If you want to read the full case study, it's open access. I'll start with the recommendations we provided, share a little bit about our methodology, and finish us out with a little about where we can go from here. Our recommendations The case study concluded with recommendations. This is an area I'd like us to do a lot more work in, because recommendations based on a case study are based on one example, and they'd obviously be much stronger based on more data! But for the conference submission, they were a necessary component. I think that the specific recommendations we gave hold up based on my experience (I'm biased, so take this as it is). These were our core recommendations. Start with high-level documentation. If you don't have any docs today, or all your docs are just in a bad way, the biggest bang-for-buck is with your high-level systems docs and process documentation. Don't have a system architecture diagram? Make it! Don't have a CI process diagram? Make it! These help you get your bearings on everything quickly, and they're also...
3rd Feb 2025

Stay updated

Get a weekly newsletter with the top 5 articles worth reading every week.

More from ntietz.com blog - technically a blog

Where I've been, and the future of this blog

Recently, I got an email from a reader who noted that I hadn't published anything in a little while, and he said he hopes I'm doing well. The truth is, some days I am and some days I'm not. I want to share a little bit about what's been going on, and what the future looks like. This is a pretty vulnerable post, so here's the deal. I'm going to tell you this, but it's just between you and me, okay? And there's one condition: you don't reach out to me to say "I'm so sorry!" When people share stories like this, it's often met with pitying responses. These often serve to make the sender feel better, not the recipient, and it feels bad to receive. I much prefer genuine connection from people who've had or seen similar experiences, or understand what I went through, or are facing something similar. I usually write my posts to educate, entertain, or a mixture of the two. This one is different. I'm not writing it to ask for pity or sympathy, but it's also not educational, and it probably won't be entertaining in a "this is fun to read" sense. The main thing I'm looking for here is connection, and maybe giving someone else on a similar journey something to hold onto. So here I am. I'm alive, and I'm writing this post. It's the first post I've written in over four months. That's the longest break I've taken from writing blog posts since I started writing regularly in 2022. What happened? what happened? enter: pain I've had nerve pain and tingling on-and-off since 2022. It was in my hands and forearms, and it was really sharp and really strong. If I type on a regular keyboard, this comes back with a vengeance. Instead, I started using Talon Voice for all my writing and coding, and eventually got a Keyboardio Model 100 which helps me mitigate the pain. The pain would only come on when it was triggered by certain conditions. A physical therapist eventually figured out some shoulder positions were contributing. I knew my keyboard was contributing. If I did something the wrong way, I'd be in pain for days afterwards, but if I did everything just right, I'd go months without any pain. The pain was with me when I started blogging regularly. The first posts in my weekly cadence were all written using my voice, not my hands. I committed code at work, pair programmed, wrote design docs, and was a very effective software engineer and leader. The pain was a little distracting, but it was not debilitating as long as I took care of my body. Accessibility tech saved my career, truly, and reduced my pain dramatically. I could not have gotten through the last four years of gainful employment without Talon, my keyboard, and the portable ergonomic setup I designed. I settled into a comfortable existence in my life: I had this oddball setup, it made me quirky but in a fun way. But then things got much worse. neurology, part 1 A year ago, I started to notice some other symptoms. They were tolerable and not very distressing. But since they were a change in something that was stable, and pointed to different potential causes than the presumed diagnosis, I wanted to get checked out to be cautious. I got a referral to neurology, and went to one of the best neurology departments in my area. We ran a lot of tests, and didn't find anything wrong. This was supposed to be relief, because it meant nothing was progressive: I shouldn't expect it to get worse, certainly not quickly. (Is this foreshadowing? It sure is!) It was also a little frustrating, because it meant we still didn't know why I had these weird sensations and pain. Three years in, no diagnosis. My doctor told me to follow up with her in a few months, and we'll keep monitoring this. I didn't follow up, because I was recovering from a planned surgery, and I was feeling pretty good. That didn't last. business ramps up A few months after my surgery, I left my job of 8 years and started my business! This was a milestone I was working toward for a while, and I was excited to dive in. I loaded up my calendar with chats. Work came in from one client, developing some software in an industry that is very privacy and security conscious. Other friends and acquaintances were happy to chat with me, and some promising leads came up. Some clients came in asking for coaching, too. Things looked so good and promising for me and my business. more tests At the same time my business was starting to ramp up, so were my nerve issues. The pain started to ramp up, and so did some unsettling sensations in my peripheral nerves. This time was different. Instead of something that I could manage and mitigate on my own, it would take over my life. But I didn't know that just yet. At this point in the story, it just felt annoying. I got an appointment with my neurologist, and went back in. She ordered more tests, and we discussed medication to manage the symptoms. Yet again, the tests said everything is normal, when my doctor and I could both clearly see that it was very much not normal. Meanwhile, the pain got worse. A month after that appointment, I was constantly at 6 or 7 on the pain scale[1]. I couldn't feel temperature in my hands, and my fingers were a little numb. My feet were burning most of the time. And I had so much brain fog that I wasn't sure if I could code a hello world example. I wasn't capable of working even one hour in a week. And we didn't know why, or what was happening to me. The only thing we could do was monitor symptoms more, and cover them up. And so I started medication. It helped, a little bit, maybe. I started using a TENS unit. It helped, for the time it was on. I started physical therapy. It helped, being forced to exercise. I worked with a dietitian nutritionist. It helped resolve other symptoms, improved quality of life. I landed a bigger client, and ramped up my work hours. I'd go through times when I worked too many hours, landing myself back on bed rest for a couple of days after. Six hours was too many. Three was maybe doable. My life felt like it was over, in a lot of ways. But we kept working on it, and adjusted my medication. Eventually, I felt mostly okay again. stable With the right medication, dietary changes, physical therapy, and (attempts at) relaxation, I got to what felt like a stable point. (Again with that foreshadowing!) I was able to take on more clients, and work more hours. That's where I am today, mostly. I say mostly because, well, today I'm actually in pain again. I've had the weird nerve symptom precursors on and off a lot recently. My fatigue is at the gate, held off for now but waiting to storm the keep. I'm writing this post with pain in my arms, but I'm typing, and that doesn't seem to make it worse. Neurology and I continue to be besties, working on our mutual hobby of debugging the weird things my body decides to do. I finally had some blood tests which were out of band one way, then the other way. I am having new symptoms, which gives us more leads to pull on. I'm still in pain, sometimes, but it's bearable and not constant. I am able to do more work every day than I have since the middle of last year. But it feels a little bit precarious. That's the life of having a chronic illness and chronic pain, especially when you don't have a diagnosis and you don't know the triggers. I have a really good life. Business is going well enough that I'm able to comfortably support my family. (That said: please do give me more business!) My personal life is also going well. And I'm making some beautiful poetry and music. I cherish this life. I'm drinking in every minute I can. I don't know if I have one more year of playing my saxophone, or sixty more. So I'm going to enjoy it and be in the now, and worry about tomorrow, tomorrow. what's next on the blog? It's probably clear that I'm not coming back to weekly blog posts. Or that if I do, it's not going to be something I can rely on doing for the long haul. But I'm finally well enough that I do have the urge to write again. The urge to dive deep into tech and do weird things with it, just to horrify you all. I'm honestly not sure what's next. I have a few ideas I want to work on, but my time is limited. My business is taking a lot of my energy, as are my personal life and some medical needs. I might end up writing more things like this. Essays that wind through a personal topic. Dives into things like Lyme disease tests and the ways in which they're broken. Explainers about all the different pain scales. And I might end up writing tech posts. Explain something that I learned recently. Make a silly, terrible idea come to life, and subject you to it share it with you. Expound on leadership topics and the human side of tech. But when will it happen? I really don't know. I had quietly launched a Patreon page this year, and I've shut that down, since I can't keep that up with all of *gestures at her body's shenanigans* this. A dream I had, and still have, is to be able to make a living from my creative endeavors. That dream seems like it will remain just a dream, but things can always change. * * * And yet. And yet, I'm happy. Dreams are great, but they can't hold a candle to life itself. Life's pretty rad. In the last few months, I've written more poetry than ever before in my life. Better poetry. Meaningful poetry, silly poetry, poems about booty calls and poems about grief. My music has taken on more expression and more meaning. I've been able to write instrumental pieces that authentically communicate an arc I had through trauma and recovery. Connections with people have formed, and deepened. New people have entered my life, enriching it more than I could ever have imagined. Old friends have shown me so much love and support through my hardest moments. This isn't what I thought my life would look like. It's both harder and better than I'd ever dared to wish for. If you're wondering, I think this one from Alberta Health Services is the clearest, most useful pain scale. ↩

17th Jun 2026 • 1 votes
You can't always fix it

I have some weird hobbies, and one of those is opening up the network tab on just about anything I'm using. Sometimes, I find egregious problems. Usually, this is something that can be fixed, when responsibly reported. But over time, I learned a bitter lesson: sometimes, you can't get it fixed. Tracking my package Recently, I was waiting for a time-sensitive delivery of medication. It used a courier company which focused on just delivering prescription medications. I opened up the tracking page on my computer, and saw the information I wanted: the medication would probably arrive around 6 PM. But... what if there's more? And what are they doing with my data? Can anyone else see it? So I peeked at the network tools, and was disappointed by what I saw. The first time this happened, I was surprised. By now, I expect to see this. And what I saw was every customer's address along the delivery route. I also saw how much the courier would get paid per stop, what their hourly rate was, and the driver's GPS coordinates (though these were sometimes missing). After the package was delivered, the tracking page changed and displayed a feedback form, my signature, and a picture of my porch. The JSON payload no longer included the entire route, but it included my address, and the payload from an easily guessable related endpoint did still contain the entire route. And that route? It included other recipients' ids, which can be used to find their home addresses, names, contents of the package (sometimes), a photo of their porch, and a copy of their signature. Um. This is bad, right? Resposibly disclosing the vulnerability I've actually found approximately this vulnerability in two separate couriers' tracking pages (and they're using different software). One of them was even worse for them, it included their Stripe private key, I suppose as a bug bounty for people without ethics. And each time I find it, I try to report it. And I fail. They don't let me report it. These companies don't list security contacts. The staff I can find on LinkedIn or their website don't have email addresses that I can find or guess. Mail sent to the addresses I do find listed has all bounced. I tried going through back channels. I messaged the pharmacy which was using this courier. I talked to my prescriber, who was shocked at this issue. And the next time I got a delivery, it came via UPS instead (they do not have a leaky sieve for a tracking page, but they did "lose" my prescription once). But I don't know if they just did that for me, the miscreant who looks at her network tools? Or did they switch everyone over to a different courier? Either way, at least my data was safe now, right? It was, until I started using a different pharmacy, and this one is back to using the leaky couriers again. Sigh. It's not my responsibility to fix this (and I can't) I got pretty upset about this at one point. There's a security issue! Data is being leaked, I must get this fixed! And someone told me something really wise: "it's not your responsibility to fix this, and you've done everything you can (and more than you had to)." And ultimately, she was right. I was getting myself worked up about it, but it's not my responsibility to fix. Sometimes there will be things like this that are bad, that I cannot fix, and that I have to accept. So, where do I go from here? I could probably publicly name-and-shame the couriers, but it would not do anything productive. It would not get their attention to fix it, and it wouldn't be seen by the folks who need to know (pharmacists and prescribers). So I'm not going to disclose the specific company, because the main thing it would do is risk me getting in legal trouble, for dubious benefit. I've already notified the pharmacists and prescribers that I know; it's on them, if they want to let anyone else know.

2nd Mar 2026 • 1 votes
Some good English word datasets

I'm working on a silly word game right now, which means I need a list of words for it. I can't rely on the system word list, since this is for a web project. I'd also like, ideally, multiple lists of words with different criteria: most common words, all words, some subsets. It's not really clear how many words there are, because what is a word[1]? And how do you find what words are in use? Or decide that something's used enough that it merits being put in a list, rather than just being a misspelling or something used once or twice? You probably don't want every mashing of keys that someone's done in there, or adjklfalkjsdfaklsd and variations are going to take up some considerable space. So that results in a lot of different word lists being available! With that in mind, here are the two best word list sources I found and some of their properties. WordNet: a while back, researchers at Princeton put together WordNet, a database of relations between words. This includes definitions and synonyms and things like that. It's no longer maintained by Princeton, but was forked and maintained with a release 1 month ago. There are libraries to load it. Wortschatz Leipzig frequency lists: A project under Leipzig University, this is a collection of word frequency lists from various sources. The English downloads page has datasets drawn from news, the web, or Wikipedia. And there are two honorable mentions, which I want to call some attention to. These are useful, but not useful for this project. /usr/share/dict/words: Unix systems come with word lists installed, which is handy for things like spellcheckers. On my system, this file contains about 480k words. This is accessible through various libraries, too. Mine does contain things like "1080", so I want something a little cleaner. It's nice to have available! Licensing isn't super clear to me, but it can be figured out and the word list could (with appropriate licensing) then be distributed with the application. Wikitionary: It's available under permissive license terms! There's a page documenting different frequency word lists, which can be used to get the top words from different contexts, like the most common words on wikipedia, in TV scripts, or in contemporary poetry! It doesn't make the cut for me since the data is prepared for human consumption rather than being machine readable. The WordNet data and Leipzig frequency lists both need to be loaded and processed, but the formats are documented and can be implemented pretty easily, especially if you have a specific subset of the data you need. I'll be using the Leipzig data most likely for my silly little word game. I might combine it with WordNet to be able to pull up definitions, but we'll see! Someday I'd like to pull some of the Wikitionary data, because it's really cool and has a lot of different frequency lists. Like the one with the 2000 most common words in contemporary English poetry. That might not make the cut for this project, but that's just crying to be used for something else. For example, I maintain that "apple tree" is a word. "Tall tree" is two: "tall" is an adjective that's used to modify "tree" which is a noun. But that's not true with "apple tree" since, "apple" isn't an adjective, it's another noun. We use "apple tree" as one singular word, and it has its own dictionary entry. I'm only slightly joking. ↩

2nd Feb 2026 • 1 votes
Reflecting on 2025, preparing for 2026

As I do every year, it's that time to reflect on the year that's been, and talk about some of my hopes and goals for the next year! I'll be honest, this one is harder to write than last year's. It was an emotionally intense year in a lot of ways. Here's to a good 2026! Reflecting on 2025 Where last year I got sick and had time black holes from that, this year I lost time to various planned surgeries. I didn't get nearly as much done, because it was also hard to stay focused with all the attacks on trans rights happening. Without further ado, what'd I get up to? Professional I helped coaching clients land job and improve their lives at work and beyond. I started coaching informally in 2024, and in 2025 I took on some clients formally. During the year, I helped clients improve their skills, build their confidence, and land great new jobs. I also helped clients learn how to balance their work and home life, how to be more productive and focused, and how to navigate a changing industry. This was one of the most rewarding things I did all year. I hope to do more of it this coming year! If you want to explore working together, email me or schedule an intro. I solved interesting problems at work. This reflection is mostly private, because it's so intertwined with work that's confidential. I learned a lot, and also got to see team members blossom into their own leadership roles. It is really fun watching people grow over time. I took on some consulting work. I had some small engagements to consult with clients, and those were really fun. Most of the work was focused on performance-sensitive web apps and networked code, using (naturally) Rust. This is something I'll be expanding this year! I've left my day job and am spinning up my consulting business again. More on that soon, but for now, email me if you want help with software engineering (especially web app performance) or need a principal engineer to step in and provide some engineering leadership. I wrote some good blog posts. This year, my writing output dropped to about 1/3 of what it was last year. Despite the reduction, I wrote some pretty good posts that I'm really happy with! I took a break intentionally to spend some time dealing with everything going on around me, and that helped a lot. I didn't get back to consistent weekly posts, but I intend to in 2026. Personal My hernias were fixed. During previous medical adventures, some hernias were found. I go those fixed[1]! Recovering from hernia repair isn't fun, but wasn't too bad in the long run. It resolved some pain I'd had for a while, which I hadn't realized was unusual pain. (Story of my life, honestly.) Long-awaited surgery! In addition to the hernia repair, I had another planned surgery done. The recovery was long, and is still ongoing. My medical leave was 12 weeks, and I'm going to continue recovering for about the first year in various forms. This has brought me so much deep relief, I can't even put it in words. Performed a 30-minute set at West Philly Porchfest. I did a solo set in West Philly Porchfest! All the arrangements were done by me, and I performed all the parts live (well, one part used a pre-sequenced arpeggiator). I played my wind synth as my main instrument, layering parts over top of myself with a looper, and I also played the drum parts. You can watch a few of the pieces in a YouTube playlist. Wrote and recorded two pieces of original music. This was one of my goals from 2024, and I'm very proud that I got it done. The first piece of music, Anticipation, came from an exercise a music therapist had me do. I took the little vignette and expanded it into a full piece, but more importantly, the exercise gave me an approach to composition. I'd like to rerecord Anticipation sometime, since I've grown as a musician significantly across the year. My second piece I'm even happier with. It's called Little Joys, and I'm just tickled that I was able to write this. I played it on my alto sax (piped through a pedal board) and programmed the other parts using a sequencer. One of my poems was published! I've written a lot more poetry this year. One of my close friends told me that I should get one of them published to have more people read it. They thought it was a good and important poem. That gave me the confidence to submit some poems, and one of them was accepted! (The one they told me to submit was not yet accepted anywhere, but fingers crossed.) You can read my poem, "my voice", in the December issue of Lavender Review. Last year's goals Every year when I write this, I realize I got a lot done. This year was a lot, filled with way more creative output than previous years. How does it stack up against what I wanted to do last year? ❓ Once again, I wanted to keep my rights. It's a perennial goal, and I did keep my rights in the state/community I live in. I'm awarding this one a question mark since my rights were under assault, and there are now many more places I cannot safely travel to. That means it's not a full miss, but not a win either. ✅ No personal-time side projects went into production! Yet another year that I toyed with the idea and again talked myself out of it. I'm taking it off the list for 2026, since the urge wasn't really even there this time. ✅ Maintained relationships with friends and family. I've had regular, scheduled calls with some people close to me. I've visited people, supported them when they needed me, and asked for support when I needed it. ❓ I did a little consulting and coaching, but didn't explore many ways to make this (playful exploration like I do on here) my living. I'm giving this the question mark of dubiousity, since I don't think I got much information from the year toward the questions I wanted to answer. ✅ Kept my mental health strong! There were certainly some challenges. What I'm proud of most is that I recognized those challenges and made space for myself. That's why I stopped blogging regularly: I needed the space to get through things with intact mental health. ❓ Did some ridiculous fun projects with code, but not as much as I wanted. The main project was making it so I can type using my keyboard (you know, like a piano, not the thing with letters on it). I had aspired to do more, and I'm glad I let myself relax on this. ✅ Wrote some original music! ✅ Also recorded that original music! It's on my bandcamp page. I am really proud of how much I did on my goals. I might be unhappy with my slipping on if it were a "normal" year where the government isn't trying to strip my rights, but you know what? I'll take it. Especially since I prioritized my health and happiness. Hopes and goals for 2026 So, what would I like to get out of this new year, 2026? These aren't my predictions for what will happen, nor are they concrete goals. They're more of a reflection on what I'd like this coming year to be. This is what I'm dreaming 2026 will be like for me. Keep my rights (and maybe regain ground). A perennial goal, I'd like to be able to stay where I am and have access to, I don't know, doctors and bathrooms. We've held a lot of ground this year. Hopefully some of what was lost can be regained. I'm going to keep doing what I can, and that includes living my best life and being positive representation for all others who are under attack. Maintain relationships with friends and family. I want to keep up with my friends and family and continue having regular chats with those I care about. We're a social species, and we rely on each other for support. I'm going to keep being there for the people I care about when they need me, and keep accepting their help as well when I need them. Spin up my business. I'm going out on my own, and I'm going to be offering my software engineering services again. By the end of the year, this will hopefully be thrumming along to support me and my family. Publish weekly blog posts (sustainably). I'm back in the saddle! This is the first post of 2026, and they're going to hopefully keep coming regularly. To make it sustainable, I'm going to explore if Patreon is a viable option to offset some of the time it takes to make the blog worth reading. Record a short album. I have a track in progress, and I have four more track ideas planned. I accidentally started writing an EP, I think??? This year I would love to actually finish that and release it. Publish more poetry. Writing poetry this year was very meaningful, and it's deeply important to me. I want to get more of it published so that I can share it with people who will also be able to get deep importance from it. * * * That's it! Wow, the year was a lot. I've put a lot of myself in this post. If you've read this far, thank you so much for reading. If you've not read this far, then how're you reading this sentence anyway? 2025 had a lot in it. There were some very good things I am very grateful for. There were some very scary and bad things that I wish had never happened. All told, it's been a long few years jammed into one calendar year. I hope that 2026 will be a little calmer, with less of the bad. Maybe it can feel like just one year. Regardless, I'm going to hold as much joy in the world this year as I can. Please join me in that. Let's fill 2026 with as much joy as we can, and make the world shine in spite of everything. The surgeon really meshed me up! ↩

5th Jan 2026 • 1 votes
A new system for organizing my writing and projects

Keeping up with regular blog posts is a challenge. To do it, I've churned through a few different organizational systems. Sometimes I have to change them due to actual life circumstances changing; other times, due to the old one just wearing off[1]. Well, my life circumstances have changed again. I'm on medical leave right now recovering from surgery[2], and I have been writing less this year anyway. So it's that time again: new system, baby. This post isn't a how-to. It's not a prescription for your own organizational system. Rather, let it be an invitation to examine your own systems, and decide whether they're serving you or not. Out with the old So what am I replacing? Before this change, my system involved Obsidian and LunaTask: Obsidian for recording ideas LunaTask for keeping track of works in progress and things that have a due date When I get an intrusive thought about how I definitely need to try to make a transistor at home in my garage[3], I put that in my list of ideas. This list of ideas contains some ridiculously bad ideas, and some very good ideas. But the thing is, I can't tell which is which when I have the idea! The ideas have to sit and marinate, and then eventually one sticks in my head long enough that it turns itself into a blog post. With most of the already completed ideas removed, that file is over 150 lines long right now. LunaTask is used to get these ideas from my brain over the finish line. I have a project called "Writing" which is kanban style. Each blog post I earnestly intend to write gets added into it, and then I keep track of which ones are waiting, in progress, and completed. This is mostly useful for posts which require code to go along with them, or which require research[4]. Posts like this one that are all prose without research go pretty fast and never enter LunaTask. The thing is, this has been showing cracks. I've stopped recording blog post ideas all that much this year, because I've been stressed from "global events" (I'm a trans woman, my wife is an immigrant, etc.) and preparing for multiple surgeries. And tracking things in LunaTask is just not working for me at all, because it's disconnected from idea tracking but ends up being its own idea tracking, since I just really want to write all the posts. To be honest, I'm not 100% sure why LunaTask isn't working for me right now for this. It might just be that I need to perturb the system a bit to make a change. But no matter what the cause, it's time to change it. In with the new The new system is simpler than the old, because I'm removing a tool. I'm taking LunaTask out of my blog toolkit, and switching to tracking everything in Obsidian. The new system is going to be smaller: an ideas page in Obsidian a works-in-progress page a task tracker for recurring blog tasks I'm using a task tracking plugin in Obsidian for the recurring tasks, because there are some things I need to do on a regular schedule. If I want to publish on Monday, that means that the post needs to be written before the weekend and edited before Monday. I'm not using task tracking for actual posts because I know from personal experience that it ends up similar to my ideas page but with structure. I'm also not using Obsidian's Bases for this, because a raw text file is just the lowest friction way I've found to do what I need. A raw text file lets me move things around freely, add notes however and wherever I want, and do freeform brain dumps. Structure is a little tyrant that kills my motivation at certain phases, so bye bye structure, we're doing a coup here. * * * So far, so good with the new system. I'm sure I'll be onto another one eventually. The most important thing, I've found, is to remain mindful of whether or not the systems are working for you. Change them once they stop working. There's this phenomenon where self-help productivity books almost always help you when you adopt a new system. But the help doesn't last forever! It seems that changing your system helps in some way, perhaps from the increased awareness and mindfulness, or maybe from new dopamine. ↩ It was a planned gender affirming surgery. The recovery is long and challenging, but I'm recovering very well. I'm very thankful for the support I have from my friends, family, and community. ↩ How hard can it be? The hubris of a software engineer knows no bounds, except for that refactor you know you should do but that you think is just a little too hard. (And yes, making a transistor would be very hard, and no, I'm not going to do it. Probably. The thoughts are still here.) ↩ I have a partially written post on Lyme disease which I do intend to complete, but it's a topic that I really want to be careful around. And so it languishes. ↩

1st Dec 2025 • 3 votes

More in programming

BazelCon 2026 recap

My now-traditional “summary” of the conference along with my own commentary and thoughts.

2 hours ago • 1 votes
The Future of CSS ✨

Every year, browser vendors collaborate via the Interop project to synchronize their efforts on new HTML/CSS/JS features. This year, there’s a ton of super exciting features being considered! In this blog post, we’ll explore the CSS of the future, to get a glimpse of what we’ll soon be able to do.

yesterday • 1 votes
Speeding up code review with `small-change`

Imprint’s average engineer is merging 4x more PRs than 2 years ago. Yay. Aggregated behind the average is something even more interesting: we have two teams that are merging 10x their PRs over that period. One engineer is merging 25x the PRs per week of our average engineer two years ago, and a number are merging 10x. That’s pretty neat, and the slope of the line suggests our average in a year is going to look much closer to today’s p90 than today’s p50. Even more importantly, we aren’t just shipping more, our quality has improved: incidents are down 42% half-over-half, and critical incidents are down 78% half-over-half. I think we’ve always known the quality/velocity tradeoff wasn’t a particularly useful construct, but that’s undeniable today. As we’ve walked this path, we–like everyone else progressing down it–have run into the problem of pull request review. The p50 pull request review took about 33 minutes to complete 2 years ago, but now takes us about 77 minutes. The slope here correlates tightly with the number of pull requests getting merged. Tightly enough that addressing it became one of my priorities for the week. We solved it! Just kidding, we’ve absolutely not solved it, but I think our current approach is an interesting one, which we call the small-change. The work discussed here was shaped and done by many folks at Imprint including Dan, Joy, Daniel, Lenny, Taylor, Ted, and Annie, among many others. Why review pull requests? There are four reasons we review pull requests: Knowledge sharing between author and reviewer – software engineering is generally learned via apprenticeship, and reviews are a primary mechanism of experienced engineers teaching others what good software looks like. We believe the current volume means that this knowledge sharing will have to move towards operating on clusters of pull requests, rather than individual pull requests Preventing errors – review has always been an expensive time to catch errors, and we believe that effective CICD along with harness verification techniques like poteto’s pstack are more effective mechanisms for preventing errors than review Preventing malicious behavior – my experience is that even careful code review will generally miss competent malicious behavior, although fortunately most malicious behavior is incompetent. We believe both sorts of behavior are best identified using a combination of fixed rules (modifying these specific objects/classes/files requires review), anti-abuse mechanisms that we’ve refined in our LLM-based member support experiences, auditing, and audit log inspection Compliance obligations in our documented controls – these can be changed, but today they require that an independent human reviews changes in a subset of our repositories In the modern development paradigm, we think there is a better solution for each of these problems. But, we also want to make these changes very cautiously. Small steps with small-change We believe we move fast by finding narrow, contained ways to validate new practices, so to iterate our way into an effective solution, we’ve developed the concept of a small-change. Here’s how it works: When a pull request is marked ready, CICD determines whether it is eligible to be a small-change. This is represented as a passing Github check. There is also a label for visibility, but it is the check itself, managed by the build and not human modifiable, that determines eligibility. (The label is used for initial filtering, but the check is still independently verified.) Something is a small-change if it meets all of these criteria: It is less than 1,000 lines of code There are no p1 or p2 findings from our ai-code-review automated review bot The author has “experience” in the service or application, defined as 10+ prior merged pull requests into that service or application’s directories. For changes working across multiple services or applications, the author must have experience in all of them to qualify Impacts fewer than N distinct services or applications. N is 1 on our frontend monorepo, and N is 3 in our backend monorepo, where typical changes will modify both a gRPC service and a common HTTP gateway Shared libraries and utilities files are not eligible for small-change Each repository has a .small_change file which allows per-path customization while we continue to tune the behaviors. For example, a service dealing with money movement can be excluded Our Slack automation tags every reference to a pull request with reacji labeling the state of that pull request, for example if it has failing tests, if it has been approved but tests are still running, or if it is ready to merge. We added a small-change reacji that indicates which of those pull requests meet the small-change criteria In our internal skills repository, we created two skills that have been distributed across harnesses: review-small-change which takes a list of repositories and reviews all open, non-draft, small-changes, including providing approval if they meet the review’s criteria (all checks pass including small-change check, and not touching on sensitive topics such as payments and security) review-pr-cluster which reviews batches of pull requests to identify common themes that came up, and suggest opportunities for discussion and adding verifications We set the social expectation that any error caused by a small-change is a failure in our system, and has to be solved at the system level: improvements to ai-code-review, to our verification mechanisms, to our CICD, to our harness, etc. This took about two days of infrequent attention to implement and rollout, although I imagine we will be tuning the knobs here for a long time. Maybe forever. fleet: centrally orchestrated harness I’ll briefly mention our other approach to reducing code review volume, which anchors on our centrally-orchestrated harness, fleet. (Which is similar to Stripe’s Minions although not following the one-shot approach in particular). We rely on fleet to implement and verify software in a highly controlled harness running in the cloud, with independent evaluation mechanisms to identify the correct number of independent reviewers for any given change. That number can be as low as one (e.g. fleet writes, one human reviews) for changes evaluated as safe. Results / next steps / reception I’ll be honest, it’s too early to give a useful result here. From early results, about 10% of changes qualify as a small-change. Those are now eligible for very fast approval, and generally get it unless they trip a flag, generally due to touching a security or money adjacent topic. While 10% is a small percentage, the core concept here is working, and ultimately will succeed or fail based on our ability to expand that percentage over the next few months in tandem with expanding our verification mechanisms to be increasingly comprehensive. This is ultimately going to fail or succeed depending on our ability to improve our verifications, which does require more difficult sorts of techniques to accomplish in low scale-complexity, high domain-complexity software than in the high scale-complexity, low domain-complexity products where many techniques like incremental rollouts are exceptionally effective. (Don’t get me wrong, they still work, they just provide less coverage when most users have different configuration and behavior.) Folks have not been uniformly excited about this, it’s a substantial change from how we’ve learned to be good engineers, and it’s uncomfortable to reevaluate whether a long-held best practice has become merely dogma. The most energizing part of the current cycle is that we get to reevaluate these practices we grew up on every week; the most painful part of the current cycle is that we’re likely to fall behind if we ever stop reevaluating them.

4 days ago • 1 votes
Building a Chestnut Launcher

The park near my house has lots of chestnuts and my kids have been collecting them like crazy (it’s actually their favorite post-school activity). We accumulated quite a hoard. I thought it would be fun to make a launcher so we had something to do with our new chestnut collection. I wanted to go with a very simple crossbow-style design (like the famous D2 item) using latex tubing and a leather pouch for holding the chestnuts. This is what I came up with. It launches chestnuts about 220 feet, and it’s simple enough to build in an afternoon. The frame is a 42 inch 2x2 and a spare IKEA bed slat for the crossbeam, glued and screwed together. A 3/8 inch eye bolt goes through each end of the crossbeam, and the latex tubing is tied to those and to the pouch from a leather shepherd’s sling. Tying the tubing was the fiddliest part. It has to be stretched while you wrap it with butcher’s twine, so I clamped a couple of scrap blocks to my workbench to hold it. I like this design because the tubing can be wrapped around the eye bolts to easily add more tension and power. The Trigger My favorite part of the design was that I decided to use an archery release like this one for the trigger. It provides a safe and reliable way to hold the tubing back, and it’s made to let go cleanly. I 3D printed a little housing that mounts the release securely to the back of the stock, and the release clips onto a loop of archery D-loop cord on the back of the pouch. Then I added a dowel for a rear grip and an old handle I had previously removed from my shop vac. How Well Does It Work? We tried it at the park and it works surprisingly well. Aimed at about 35 to 40 degrees, it sends our chestnuts (on the small side, about 10 to 15 grams) about 220 feet. Thanks to the archery release, we haven’t had a single misfire. I got curious and did some rough math. To go that far with air drag, the chestnuts are leaving at somewhere around 85 to 100 mph, which works out to about the same energy as a paintball. So safety glasses are important and you never point it at anyone. You can find the 3D print on Printables and a full build guide on Instructables. Make sure to always use it with adult supervision :)

4 days ago • 1 votes
Organising my cross-stitch patterns

I have a lot of digital cross-stitch patterns and until recently they were a mess. My “collection” was a series of several hundred PDFs, disorganised and spread across my disk. Recently, I was looking for a pattern and it took me several minutes to find it. I had a brief moment of panic, thinking that I’d lost it, and the website this pattern came from is long since gone. Fortunately it did turn up, but it was clear I had to organise my pattern collection. Some people would use apps like Pattern Keeper or Flosshaven, but I just created another static website on my media drive. This is what it looks like: The patterns are arranged in a masonry layout with a preview thumbnail for each pattern, which is normally the first page of the PDF. If a pattern has multiple files – for example, different files for colour and black-and-white printing – there’s a list of links below the thumbnail. I can also add a source link to where I bought the pattern, if I want to find more patterns by the same author. Internally, it’s structured like my other static websites. The metadata for the patterns is stored in a JavaScript file, and then I have an HTML page which renders that metadata in this visual design. My pattern collection doesn’t change very often, so I’m adding new files by hand. There are no sorting or filtering options, because my collection is small enough that they’re unnecessary. I can scroll through the entire list in less than a minute and find whatever I need. I’d like to start making my own clothes soon, and I expect to copy this design to store clothing patterns. This collection now sits alongside my saved bookmarks, podcasts, TV shows, and more. I can keep all my patterns organised, and I won’t lose them in the depths of my hard drive. Technical tricks There are a couple of technical pieces I’m quite pleased with in this process: Masonry layout. I love the cascading grid style of a masonry layout, and I think they’re great when you have variable-sized content – like my pattern cards. I’ve been using them for over a decade; screenshots of my early web apps show my experiments with David Desandro’s Masonry.js library. Masonry layouts are now a native feature of CSS called “Grid Lanes”, which is simpler and more performant than the JavaScript approach. I’m excited to use these layouts in even more places. Thumbnails of PDFs. Most digital postage patterns are shipped as PDFs, and I’m creating the thumbnail images with my create_thumbnail tool. I had to extend my tool to support PDFs, which turned out to be straightforward with the pdf_oxide crate. I’d not come across Oxide before, but it’s a cross-language library for working with PDFs, and I can imagine using it in future. A coloured stripe for the palette. In the metadata for each project, I have the complete list of DMC thread colours and the pattern dimensions. I have a lookup table that converts DMC thread colours to hex codes, and then I’m able to create a linear gradient in CSS to render a coloured stripe of the pattern colours. Here’s an example from a pattern with four colours: border-bottom: 12px solid transparent; border-image: linear-gradient( to right, #7a451f 0%, #7a451f 25%, #985e33 25%, #985e33 50%, #e4bb8e 50%, #e4bb8e 75%, #361f0e 75%, #361f0e 100% ) 1; Building the HTML, CSS, and JavaScript was very quick – I have notes on how I build my media sites, and I’ve done it plenty of times before. I threw together the initial prototype in less than 15 minutes. The longer part was finding all the PDFs scattered across my disk – but now that’s done, and I know exactly where to find my patterns. [If the formatting of this post looks odd in your feed reader, visit the original article]

a week ago • 1 votes
📚 BoredReading

You seem to be enjoying this.

Join free to unlock everything.

Create free account

Already have an account? Sign in