More from Bryan Braun - Blog
A few weeks ago, I was building a server-side API client. I had written the code and tested it in isolation. Everything looked good. Unfortunately, when I included it in the main service, I started seeing errors. I decided to try asking an AI tool for suggestions. I gave it the error message and a bunch of context. It gave me a solution with a detailed explanation. The errors went away. But the solution didn’t sit right with me. It was a bit complex, introducing more layers of code and various protections. The errors were gone, but I couldn’t clearly explain why it worked, and that was bothering me. While the code was being reviewed, I decided to take another look. I brought back the error and spent some time digging into the stack trace. That’s when I made the discovery: it was an environment issue. All I needed to do was set an environment variable and the issue would be fixed. The AI-provided code had been masking the real issue, quietly suppressing the error, and hiding the truth in its complexity. Now this is the part of the post where I’m supposed to criticize AI programming tools. I won’t be doing that. This isn’t an AI problem. I remember the first time I tried to fix a memory leak. Certain iPhone users would load the webpage, interact for a while, and then randomly the webpage would crash. We struggled to diagnose the issue (Safari’s devtools weren’t great at the time). We thought we fixed it several times but the issue kept coming back. Why? Because we didn’t understand the problem. We kept digging and eventually we found it: one of our dependencies was storing massive amounts of data on the window object and it wasn’t getting cleaned up. We added a cleanup step and the problem was gone for good. Since then, I’ve adopted a mantra: you can’t fix a problem you don’t understand. It doesn’t matter if the “fix” comes from AI, Stack Overflow, or trial-and-error. If I don’t understand the problem, I feel unsettled until I do.
Here are some things I made in 2024: Music Box Fun: Advanced Editing (a new major feature): Adds multiple-note selection for bulk operations on notes (like deletion, copy/paste, nudging and dragging) Also includes a “space editor” for arbitrarily adding/removing space anywhere in the song Includes other niceties like note highligting during playback and pitch highlight on hover Music Box Fun songs I made: Elliott’s Theme (Stardew Valley) in 15-note and 30-note versions Bluey Theme Song Jupiter Theme (The Planets) 11 new projects added to Let’s Get Creative, now available at a new domain name: https://letsgetcreative.today The Firefly Building in Minecraft (if you know, you know) 13 blog posts on bryanbraun.com, including a companion repo to my post on unusual Git IDs. I’m happy with this list. It was a year of many challenges. In February we got hit by a flooded basement and an emergency hospitalization which left my wife with limited mobility for a month. It was a difficult time and I’ll be forever grateful for the family and friends who helped us get through it. It was also a year of growth for my kids in particular, bringing many new parenting challenges. At the same time, I have so much to be grateful for. My wife and I hit our fifteenth anniversary and our relationship has grown stronger despite (or perhaps because of) the storms we’ve weathered. Every year brings new opportunities and challenges and it’s a privilege to have a committed partner that I can face them with. 🚵🏻♀️🚵🏻♂️ I wish you all the very best in 2025.
Here are some more links to things that I keep thinking about. I shared a bit more detail on these ones than I usually do—there were so many good quotes to include. Enjoy! Selfishness & Therapy Culture Earlier this year, there was a post in the New York Times called “Sometimes, Forgiveness is Overrated”. Selfishness & Therapy Culture is a brilliant critique, both of the NYT post and of the culture that produced it. “Who in the world could possibly look out at contemporary society and think that the message ‘put yourself before other people’ isn’t loud enough? Every women’s site on the internet preaches this message. Every hustle bro on Threads preaches this message. Every therapist between San Diego and Sacramento preaches this message. Every eight-word meme in overly elaboratee cursive font on Pinterest preaches this message. … There’s the girlboss version and the Joe Rogan bro version and horoscope obsessive version and the Wall Street grindset version and the fitness guru on trenbolone version…. Justification for selfishness is not in short supply. It is the water in which we swim.” My opinion: the celebration of selfishness is a form of societal sickness that we have, and it isn’t new. Faith practices that center on forgiveness and selflessness are part of the social infrastructure our forefathers erected to fight the sickness, and when we erode them, we do so at our own peril. The Morality of Having Kids in a Magical, Maybe Simulated World This post is a reaction to the recurring sentiment that perhaps it is immoral to have children in a world threatened by climate change. The “evidence for a simulated world” part is a bit farfetched, but what interested me the most was the idea of framing human progress in the terms of “ENERGY: The Game.” It gave me this feeling like, oh, we’re all collectively playing this game1, and it’s going somewhere, so what is my role? Instead of playing for myself, or my family, or my country, I could be playing for humanity, in its fight against the elemental foe. In this game, is there anything more noble then working to push technology forward, creating value out of nothingness, helping to create abundance for all humanity? You should be working on Hardware I work in software but I studied mechanical engineering, so I have a deep respect for those who work in hardware (like Casey Handmer, the author). I love how this post calls out the needs in the world and raises your aspirations to work on them: “You only get a few chances to work on really big projects, to build the future, to move humanity forward.” “Most hardware concepts will never even be dreamed, let alone designed, built, and brought to market. There are many, many more important, good businesses to build than there are people building them. When you build something, you can accelerate the future by decades!” The whole post is inspiring, not to mention the follow-up post How to learn Hardware, which included this wisdom: “It is always easier to learn things you enjoy doing. The art lies in finding ways to enjoy the things that are necessary…. and finding ways to avoid enjoying to excess things that are counterproductive to your mission in life.” The Well-Rounded Engineer Another one from Casey Handmer (I’ve been reading through his archives). In this one, he explains that all nontrivial engineering efforts eventually encounter “the coordination problem.” It is very common for engineers to be oblivious of it, which manifests itself in things like complaints about management being inept, or resentment that their work was “thrown away.” Here, Casey argues that elite engineers should understand the coordination problem, what causes it, and ways to resolve it. I’ve historically avoided the management track because I enjoy creating things and people are messy. That said, management exists to help solve the coordination problem and this post helped me see that I ought to develop a working understanding of management if I ever want to create something nontrivial (and I do!). Casey’s blog has quickly become one of my favorites. You Don’t Have Time to Read Books That Won’t Change Your Life We’ve all read a book that changed our life, right? Given that there’s 50 million+ books in existence, there are likely hundreds of thousands of other life-changing books out there that we only haven’t read because we haven’t found them yet. This post pushed me to imagine what my life might look like if I read twice as many “life-changing books” as I currently do, and how I might do that. I’ve been on a reading kick recently (a book a week for the past six weeks!) and I feel like it’s added a richness to my life that I don’t get from podcasts or music. 1 "It's like we got handed a save file of a game, where others put in millions of hours of work, and we can decide what game we want to play in the future." - Kurzgesagt
You can search Github for unusual commit IDs: There are over 2k commits starting with 0000000! While looking for commits like these, I started to become suspicious that people were intentionally modifying their commits IDs to be unusual: A commit ID of eeeeeee, with a message of "eeeeeee", created by a user named "eeee". What are the odds that this user happened to commit seven consecutive commits, all with an ID of "defaced"? Sure enough, there are tools you can use to generate “vanity” commit IDs (like git-vanity-hash). These tools work by using the “brute-force” method. Basically, they create a commit, check the hash, and if it doesn’t match, they increment a piece of data in the commit header and try again. That’s pretty clever but I’m more interested in unusual commit IDs that occur naturally. How often do they happen? Have I ever created one before? Searching my commits I decided to use Github’s CLI tool, gh, to query the Github API and pull down a list of my public commits: gh search commits --author bryanbraun --json commit --jq ".[].commit.tree.sha" --limit 1000 This worked but it has a maximum limit of 1000 commits (my public total is closer to 4k). Eventually, I found a way to get them all by writing a bash script to break up my queries by year, generating one file per query, and combining the files when done: #!/bin/bash # To prevent API rate limits, set a personal access token to the GITHUB_TOKEN # environment vairable in your terminal before running this script. username="bryanbraun" start_year=2012 end_year=2024 # Create a file for each year for year in $(seq $start_year $end_year); do next_year=$((year + 1)) echo "Fetching commits from $year to $next_year..." gh api -X GET \ "/search/commits?q=author:$username+committer-date:$year-01-01..$next_year-01-01" \ --header "Accept: application/vnd.github.cloak-preview" \ --paginate \ -q '.items.[].sha' >> "commits-$year.txt" done # Combine all files into one cat commits-*.txt > all_commits.txt # Remove unused files for year in $(seq $start_year $end_year); do rm "commits-$year.txt" done The result is a 4000-line file with one commit ID per line: Now I just needed to scan my commit IDs for unusual patterns. Grep is good at this kind of thing so I put together a bash script that uses grep to do various checks: #!/bin/bash # Define the input file containing commit SHAs input_file="all_commits.txt" echo "Analyzing patterns in the first 7 characters of commit SHAs..." # Check 1: SHAs where the first 7 characters are the same echo "\n1. SHAs where the first 7 characters are the same:" grep -E '^(.)\1{6}' "$input_file" # Check 2: SHAs starting with a palindrome (e.g., "abcdcba") echo "\n2. SHAs starting with a palindrome:" grep -E '^(.)(.)(.)(.)\3\2\1' "$input_file" # Check 3: SHAs where the first 7 characters form an ascending sequence echo "\n4. SHAs where the first 7 characters form an ascending sequence:" grep -E '^(0123456|1234567|2345678|3456789|456789a|56789ab|6789abc|789abcd|89abcde|9abcdef)' "$input_file" # Check 4: SHAs where the first 7 characters form a descending sequence echo "\n5. SHAs where the first 7 characters form a descending sequence:" grep -E '^(fedcba9|edcba98|dcba987|cba9876|ba98765|a987654|9876543|8765432|7654321|6543210)' "$input_file" # Check 5: SHAs where the first 7 characters form a repeating pattern (e.g., "abababa") echo "\n6. SHAs where the first 7 characters form a repeating pattern:" grep -E '^(.)(.)\1\2\1\2\1' "$input_file" # Check 6: SHAs where the first 7 characters are vowels only echo "\n7. SHAs where the first 7 characters are vowels only:" grep -E '^[aeiouAEIOU]{7}' "$input_file" I ran this and got something! One of my commits was a palindrome: c5a7a5c c5a7a5c, my most unusual commit ID, was created over ten years ago! It’s not the most beautiful commit ID but I’m pretty happy that I found something. What else could we do? My list of checks was pretty short, so we could expand it if we wanted. Here are some ideas: Check if the first seven characters are all letters, or all numbers (e.g., “afddcbf”, “2950312”). Check if the first seven characters are composed of only two distinct characters (e.g., “a44aaa4”). Check commit IDs against a list of words constructed from hexadecimal characters (e.g., “baff1ed”). Check if the first seven characters are in alphabetical order (e.g., “accdfff”). Check if the first seven characters are in numerical order (e.g., “0035789”). Check for interesting patterns outside of the first 7 characters of the commit ID. I actually tried that first idea but I found that the “all numbers” case was too common (it found over a dozen matches in my commit history). You gotta strike the right balance. It would be fun to put together a web interface where people could put in their Github username and scan their own commits, but I’ve come to terms with the fact that there’s not enough time in the world to build all the interesting little websites that ought to exist. I used ChatGPT to help me build the scripts, which made it possible to punch out this analysis in a single afternoon. If it took any longer, I likely wouldn’t have attempted it. This is a perfect example of AI-enhanced development making me more ambitious with my projects. I put all the scripts in a public repo at bryanbraun/unusual-commit-ids. Feel free to fork it, download it, and scan your own commits. If you find any unusual commits in your own history, you should share them in the comments (naturally occurring commits only)! Finally, if you thought this was interesting, you may like my other git commit-related projects: Commit colors Commit haikus (a now-retired twitter bot)
I have a /now page, which I use to tell people what I’m up to these days. I like the concept of “now pages” but I felt like it would be better if it had an RSS feed. The feed would give interested parties a way to subscribe to life changes. The problem is that RSS feeds aren’t really designed for a single page. It’s more for a content collection, like blog posts or podcasts. Still, is there a way to make it work? To have a single page, publishing to subscribers every time it’s updated? Unique IDs In RSS feeds, each entry is supposed to have a unique ID. Here are some examples: Atom <entry> <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id> <title>Atom-Powered Robots Run Amok</title> <link href="http://example.org/2003/12/13/atom03"/> <updated>2003-12-13T18:30:02Z</updated> <summary>Some text.</summary> </entry> JSONFeed "items": [ { "id": "1", "content_html": "<p>Hello, world!</p>", "url": "https://example.org/initial-post" } ] These IDs are intended to be globally unique and unchanging: id (required, string) is unique for that item for that feed over time. If an item is ever updated, the id should be unchanged. New items should never use a previously-used id. JSONFeed Version 1.1 Docs Changing the ID is bad because it causes old posts to resurface as new posts in people’s feed readers. Usually you don’t want this, even when you’re updating an old post. But in my case we do want this. If I only publish a single entry and include the current date in the ID, it’s unique every time I rebuild the feed (i.e., whenever I update the /now page). And just like that, every update is a new publish. Is this bad and should I feel bad? I’m deliberately disobeying the spec to get the result I want. Often, in the dev world, these kinds of things come back to bite you. Is there a better way to do this? Well, I could treat my /now page as a content collection, with each new entry being published as new post, never deleting or overwriting old entries (basically a microblog just for life updates). It’s doable, but it diverges from the simplicity of having a single document at a single url. At that point, I might as well insert life updates into my normal blog, which works but isn’t appropriate for many types of blogs. One issue with changing IDs is that small revisions to the /now page republish the whole page, making it hard for subscribers to see what changed. I could mitigate this by including a link to the diff on Github (version control FTW!), but it’s not the most user-friendly solution. Anyway, I’m going to roll with it for now. If anyone wants to do a similar experiment, feel free to check out the feed template in my repo.
More in technology
Introduction Selecting the RAM Opening up Replacing the RAM Reassembly References Introduction I do virtually all of my hobby and home computing on Linux and MacOS. The MacOS stuff on a laptop and almost all Linux work a desktop PC. The desktop PC has Windows on it installed as well, but it’s too much of a hassle to reboot so it never gets used in practice. Recently, I’ve been working on a project that requires a lot of Spice simulations. NGspice works fine under Linux, but it doesn’t come standard with a GUI and, more important, the simulation often refuse to converge once your design becomes a little bit bigger. Tired of fighting against the tool, I switched to LTspice from Analog Devices. It’s free to use and while it support Windows and MacOS in theory, the Mac version is many years behind the Windows one and nearly unusuable. After dual-booting into Windows too many times, a Best Buy deal appeared on my BlueSky timeline for an HP laptop for just $330. The specs were pretty decent too: AMD Ryzen 5 7000 17.3” 1080p screen 512GB SSD 8 GB RAM Full size keyboard Windows 11 Someone at the HP marketing departement spent long hours to come up with a suitable name and settled on “HP Laptop 17”. I generally don’t pay attention to what’s available on the PC laptop market, but it’s hard to really go wrong for this price so I took the plunge. Worst case, I’d return it. We’re now 8 weeks later and the laptop is still firmly in my possession. In fact, I’ve used it way more than I thought I would. I haven’t noticed any performance issues, the screen is pretty good, the SSD larger than what I need for the limited use case, and, surprisingly, the trackpad is the better than any Windows laptop that I’ve ever used, though that’s not a high bar. It doesn’t come close to MacBook quality, but palm rejection is solid and it’s seriously good at moving the mouse around in CAD applications. The two worst parts are the plasticy keyboard and the 8GB of RAM. I can honestly not quantify whether or not it has a practical impact, but I decided to upgrade it anyway. In this blog post, I go through the steps of doing this upgrade. Important: there’s a good chance that you will damage your laptop when trying this upgade and almost certainly void your warranty. Do this at your own risk! Selecting the RAM The laptop wasn’t designed to be upgradable and thus you can’t find any official resources about it. And with such a generic name, there’s guaranteed to be multiple hardware versions of the same product. To have reasonable confidence that you’re buying the correct RAM, check out the full product name first. You can find it on the bottom: Mine is an HP Laptop 17-cp3005dx. There’s some conflicting information about being able to upgrade the thing. The BestBuy Q&A page says: The HP 17.3” Laptop Model 17-cp3005dx RAM and Storage are soldered to the motherboard, and are not upgradeable on this model. This is flat out wrong for my device. After a bit of Googling around, I learned that it has a single 8GB DDR4 SODIMM 260-pin RAM stick but that the motherboard has 2 RAM slots and that it can support up to 2x32GB. I bought a kit with Crucial 2x16GB 3200MHz SODIMMs from Amazon. As I write this, the price is $44. Opening up Removing the screws This is the easy part. There are 10 screws at the bottom, 6 of which are hidden underneath the 2 rubber anti-slip strips. It’s easy to peel these stips loose. It’s als easy to put them back without losing the stickiness. Removing the bottom cover The bottom cover is held back by those annoying plastic tabs. If you have a plastic spudger or prying tool, now is the time to use them. I didn’t so I used a small screwdriver instead. Chances are high that you’ll leave some tiny scuffmarks on the plastic casing. I found it easiest to open the top lid a bit, place the laptop on its side, and start on the left and right side of the keyboard. After that, it’s a matter of working your way down the long sides at the front and back of the laptop. There are power and USB connectors that are right against the side of the bottom panel so be careful not to poke with the spudger or screwdriver inside the case. It’s a bit of a jarring process, going back and forth and making steady improvement. In addition to all the clips around the board of the bottom panel, there are also a few in the center that latch on to the side of the battery. But after enough wiggling and creaking sounds, the panel should come loose. Replacing the RAM As expected, there are 2 SODIMM slots, one of which is populated with a 3200MHz 8GDB RAM stick. At the bottom right of the image below, you can also see the SSD slot. If you don’t enjoy the process of opening up the laptop and want to upgrade to a larger drive as well, now would be the time for that. New RAM in place! It’s always a good idea to test the surgery before reassembly: Success! Reassembly Reassembly of the laptop is much easier than taking it apart. Everything simply clicks together. The only minor surprise was that both anti-slip strips became a little bit longer… References Memory Upgrade for HP 17-cp3005dx Laptop Upgrading Newer HP 17.3” Laptop With New RAM And M.2 NVMe SSD Different model with Intel CPU but the case is the same.
Jez Corden writing for Windows Central: EXCLUSIVE: Xbox's New Hardware Plans Begin With a Gaming Handheld Set for Later This Year, With Full Next-Gen Consoles Targeting 2027 Microsoft is working with a PC gaming OEM (think ASUS, Lenovo, MSI, Razer, etc.) on an Xbox-branded gaming handheld, surprisingly slated
Forget GB Railways and GB Energy... how about GB Drones?
Today marks day 13 of using the iPhone 16e as my primary phone, and after this review goes live, I'll be moving my eSIM back to the 16 Pro that I use day to day. I intended to use this phone for a month before going back to