Best practices for code review when you’re the author.
It's easier than you think to write an exceptional software tutorial. You can stand out in a sea of mediocre guides by following a few simple rules.
Best practices for code review when you’re the author.
Not many people remember this 2005 documentary featured early interviews with Paul Graham, Aaron Swartz, Alexis Ohanian, and Steve Huffman.
One-day shipping: how hard could it be?
Working around manufacturing delays
Nix is a tool for configuring software environments according to source files. I’ve been hearing more and more about Nix on Hacker News and Twitter. The idea of it appeals to me, so I’ve been tinkering with it over the past few weeks. My history with infrastructure as code Ten years ago, I discovered Salt, a tool that allows you to define a computer system’s configuration in source code. I loved the idea of a git repo that defined what services were installed on my computers and VMs. I could blow away the computer, re-run the configuration tool, and get it back to the same state.
I always run into issues installing Jellyfin on TrueNAS core. I fix them, and then I forget a few months later, so these are just my notes to myself of how to install Jellyfin on TrueNAS core. Instructions Install based on these instructions: https://github.com/Thefrank/jellyfin-server-freebsd/blob/main/Installation_TrueNAS_GUI.md#the-advanced-way We need to follow the advanced instructions because TrueNAS plugins are deprecated. Gotcha: Jellyfin server is not available The first few loads after installing, an error will appear saying Jellyfin isn’t available. For some reason, waiting a few minutes fixed the issue and let me create a new account.
I’m still a Nix beginner, and one thing I couldn’t figure out until recently was how to keep parts of my configuration.nix file under source control. My goal I’d like for my Nix configuration files to be modular and reusable, so depending on the system or flake, I can pull in only the configuration files I need. I’d like all my Nix configuration files to be under source control so that different systems can depend on different versions of any file so I don’t have to upgrade every system to the latest version of each configuration file at the same time.
Scrambling to meet demand
How do I come up with $250k in cash?
Zig is a new, open-source programming language designed to replace C. I’m still a Zig beginner, so I’m trying to learn the language by using Zig to rewrite parts of existing C applications. One of the first challenges I encountered with Zig is understanding strings. I couldn’t find detailed documentation about how Zig strings work when calling C code, so I’m sharing my findings in case they’re helpful to others who want to use Zig to call C.
I read Simon Willison’s post about using Llamafile to experiment with open-source chatbots / LLMs. He made it sound so easy, so I decided to try it out. One of my longtime hobby projects is WanderJest, a site for finding live comedy. One of the challenges of that site is that the canonical information about an upcoming show is often the poster for it. Here’s an example: I’ve been scraping this information by hand, but that’s tedious and time-consuming.
When I work in my own repositories these days, I always add a Nix flake to the repo so that I can spin up a working development environment on any system with a single command. What do I do when I’m working in someone else’s repo and they don’t want to adopt Nix flakes? Normally, I’d just add the file to my copy of the repo and gitignore it locally so I don’t commit my personally-specific files with the rest of my changes.
How can I delegate more?
Zig is a new, independently developed low-level programming language. It’s a modern reimagining of C that attempts to retain C’s performance while embracing improvements from the last 30 years of tooling and language design. Zig makes calling into C code easier than any other language I’ve used. Zig also treats unit testing as a first-class feature, which the C language certainly does not. These two properties of Zig create an interesting opportunity: Zig allows you to add unit tests to existing C code. You can do this without rewriting any of your C code or build logic.
Given how much urban design affects our lives, it’s surprising how little we think about and participate in it. This book was eye-opening in terms of the way I look at cities and how its inhabitants interact with them. I took for granted the idea that cities should be friendly to car-travel, but the book highlights many ways in which a focus on car-friendliness makes cities worse overall. It was interesting to see examples of how cities can flourish when they prioritize the needs of pedestrians, bicyclists, and public transit.
The slow transition to third-party fulfillment
Five years ago today, I quit my job as a developer at Google to create my own self-funded software business. This is a review of my last year and what I’ve learned so far about bootstrapping software businesses.
Mistakes I made working with my first design agency.
Getting out of “urgent mode”
For the past few months, I’ve been curious about two technologies: the Zig programming language and Ethereum cryptocurrency. To learn more about both, I’ve been using Zig to write a bytecode interpreter for the Ethereum Virtual Machine. Zig is a great language for performance optimization, as it gives you fine-grained control over memory and control flow. To motivate myself, I’ve been benchmarking my Ethereum implementation against the official Go implementation.
Have you ever used archive.org’s Internet Wayback Machine? It’s a free tool that’s been archiving the web since 1996. So, if you want to see what Google looked like in 1999, they’ve got it. Internet Archive capture of Google from April 22, 1999 ArchiveBox is like your own, personal Internet Wayback Machine. It’s free and open-source, and you can use it to archive most websites.
My notes and self-critiques from speaking at PyGotham.
Using profiling tools and debugging techniques to improve performance of PicoShare.
I’m skipping the retrospective this month.
TinyPilot gets its first real office.
With no idea what I was doing, I hired a cartoonist to illustrate my blog. The results were surprisingly positive.
I recently bought my first-ever managed networking switch, a TP-Link JetStream TL-SG3428X. The main feature of a managed switch is that it lets you segment your network into VLANs. I was excited about this functionality, but it took me hours of trial and error to get VLANs working. I found TP-Link’s VLAN documentation lacking, so I’m sharing my notes in case they’re helpful to others.
Eliminating myself from the critical path on releases
Improving my video recording workflow
No retrospective this month.
Update (2024-07-12): I’ve received more inquiries than I expected, so I’m now closing applications. I’m looking for someone to take over my old content website, Is It Keto. Is It Keto is for sale I worked on the site on and off between 2019 and 2020, but I no longer have time for it, so it’s just been neglected for the past several years. Still, it consistently earns $1-2k/yr in fully passive revenue.
I’m teaching a small-group, live course about attracting readers to your blog through Hacker News. Sign up by Monday (June 24th) to reserve your slot. Why take a class with me? My blog receives 300k-500k unique readers per year. After Google, Hacker News is the primary way that new readers find my writing. My blog receives 300k-500k unique readers per year, with Hacker News largely connecting me with new readers.
Worry when long-term tasks stop.
Using only a Raspberry Pi and an $11 video capture dongle, you can create your own KVM over IP device, allowing you to send keyboard input to a remote computer and capture its display.
I’m safe and healthy, but my businesses have taken a tumble.
A walkthrough for setting up Sia in Docker in Synology DSM
I recently read Julia Evans’ latest zine about git, and one of her tips was to configure your terminal shell prompt to show the git status. Julia’s terminal prompt looks like this: ~/work/homepage (main) $ main is Julia’s current git branch. When she’s in the middle of a git operation like bisect or merge, the terminal changes to this: ~/work/homepage (main|MERGING) $ It had never occurred to me to customize my shell prompt, but I immediately recognized the value.
I’m coming back to my blogging course.
My friend Cory Zue has been publishing his live coding sessions, so I decided to watch one and record my notes. My background vs. Cory’s I’ve read a lot of Cory’s blog. We’re both Python developers, but he specializes in Django, whereas I’ve always worked with thinner frameworks like Flask. I have no experience with Django, but I’m comfortable in Python.
Last week, I was listening to the CoRecursive podcast interview with PowerShell’s lead architect, Jeffrey Snover. One moment in that interview has been stuck in my head the whole week is when Snover argues that graphical user interfaces (GUIs) are inherently “antisocial”: I realized that — you know, that the mouse is antisocial. The GUI is antisocial. So what’s that mean? You have a problem to solve, and you solve it with the GUI. What do you have? A problem solved.
Easing back into work.
I’ve been interested in Ethereum the past year, especially the Base ecosystem. The problem is that after hours of reading about Base, I still don’t get what Base is. Every few months, I check back in on the Base website’s developer section to see if there’s a path to building on Base for a beginner, and the path seems to be “here are some disparate tutorials for very specific things, and if you have questions, come ask us on Discord.”
I found it eye-opening in terms of understanding how municipal governments work in practice and how perverse incentives lead to poor community outcomes. It had a huge impact on the way that I think about where to live and what policies I support in local government. This book complements Happy City in that both books explore what characteristics of a city make it attractive for residents to live there but also how legislation often yields the opposite results.
A few weeks ago, NVIDIA released Nemotron, a large language model that they derived from Meta’s Llama 3.1 70B. NVIDIA claimed at release that Nemotron outperformed GPT-4o and Claude 3.5 Sonnet on certain benchmarks. That was exciting news, as my experience with self-hostable AI models is that they trail commercial models by about a year in terms of accuracy and quality. I decided to test out Nemotron with a few simple coding tasks to see how it compared to commercial models like Claude 3.5 Sonnet.
Last week, I saw an interesting article on the /r/legaladvice subreddit. An e-commerce business owner was complaining that a customer was suing because the merchant had been sending the customer promotional emails for years that the customer never agreed to. The author deleted the post a few days later, but I found a copy of the text. The merchant was indignant and felt like it was a shakedown, but I was 100% on the customer’s side. The merchant is in the wrong for spamming their customers with promotional emails they never requested, and so the merchant should suffer financial repercussions.
Taking my development VMs to the next level
I have a few toy utility apps that I run 24/7 on cloud infrastructure. One example is PicoShare, a simple web app that makes it easy for me to share files with friends and teammates. There are several convenience apps I would run if it were easy to run them constantly. But there’s enough friction to running even a simple app 24/7 that I don’t do it. In the past, I’ve tried running toy apps on my home server. I’ve set up cron jobs and systemd services, but inevitably something breaks, and I get tired of fixing it and just let the service die.
The cryptocurrency language barrier There’s an unforunate language barrier among technologists right now. Cryptocurrency enthusiasts are excited about the ecosystem and what’s going on in crypto-world right now. They’re trying to bring new people in, but they’re often so entrenched in their crypto bubble that they struggle to explain any crypto stuff to non-crypto people. I feel like I’m a good candidate to bridge the language gap, as I understand the fundamentals of cryptocurrency but I haven’t been following any crypto stuff closely for about seven years.
I build this blog using Hugo, a popular static site generator. The way Hugo works is that when I create a new blog post, Hugo generates a default template that looks like this: --- title: "My New Post" date: 2024-11-16T20:33:09-04:00 --- The boilerplate for the post contains a publication time with a timestamp. But the timestamp obviously isn’t the time that I published the post, as I’ve just started writing it.
If you’re a liberal who’s interested in becoming a radical progressive, this is a good book for you. If you’re anyone else, you’re probably not the target audience.
A complete walkthrough of how I find freelance writers, screen them, and train them to work with me.
An exercise in integrating Docker, Google Cloud Storage, and the gcsfuse utility.
My router runs OPNSense Business. I like having an open-source router, but I have a few gripes with it. My biggest issue is that, by default, OPNsense can’t resolve hostnames on my local network. Why can’t OPNsense resolve local hostnames? For every other router I’ve owned in my life, if there’s a computer on my network named foo123 and I run ping foo123 from my main desktop, then everything just works. My desktop successfully pings foo123.
There’s an excellent Go testing pattern that too few people know. I can teach it to you in 30 seconds. Instead of writing Go tests like this: // The common, unrefined way. username := GetUser() if username != "dummyUser" { t.Errorf("unexpected username: got %s, want: %s", username, "dummyUser") } Write your tests like this, beginning each assertion with if got, want :=: // The underused, elegant way. if got, want := GetUser(), "dummyUser"; got != want { t.Errorf("username=%s, want=%s", got, want) } The if got, want :=: pattern works even better in table-driven tests. Here’s an example from my library for parsing social media handles:
A year ago, I listened to an interview with Jesse Pollak on an episode of Into the Bytecode. Jesse works for Coinbase, and he noticed that lots of developers building apps on top of Ethereum were solving the same problems over and over again. He started a project at Coinbase to create a layer on top of Etherum called Base. Base would get Ethereum developers up and running faster because they could use shared solutions to these common problems.
I accidentally hoarded TinyPilot’s release process.
I have a few Samsung SSDs, and I always have trouble remembering the process of secure erasing them, as Samsung Magician software is terrible. Here are my notes for overcoming Samsung Magician’s gotchas in the process of secure erasing a Samsung SSD. You need a Windows or MacOS system with a Samsung SSD attached This requirement drives me crazy, as Samsung Magician is creating a bootable USB disk, so it shouldn’t care what’s on your current system, but it does. And Samsung Magician only exists for Windows, MacOS, and Android, so if you’re on Linux, you can’t use it.
Recently, when I’m having trouble sleeping, I look for software to fuzz test. Earlier this week, I thought back to Fady Othman’s post “Meta Bug Bounty — Fuzzing ’netconsd’ for fun and profit.” It’s a good tutorial about fuzzing code exhaustively. Like most fuzzing blog posts, I found the work a bit difficult to reproduce because it requires the reader to figure out how to replicate the author’s environment and toolchain.
Compatibility: These instructions work as of Proxmox 8.x and NixOS 24.05. One of the stumbling blocks I ran into when trying out NixOS was that I couldn’t run it under Proxmox, my preferred virtual machine server. Through some trial and error, I figured out how to install NixOS as a Proxmox container. Download the NixOS container image First, download the latest NixOS x86_x64 lxdContainerImage image. For other hardware architectures, see this GitHub comment.
I finally found a solution that makes VS Code work consistently with Zig, so I’m sharing my setup in the hope that it saves someone else a headache. Zig extension for VS Code working correctly Before I landed on a working solution, I kept running into issues with Zig version mismatches or VS Code completely failing to recognize Zig semantics and failing over to naive autocomplete.
The term “cold email” refers to emailing someone who you’ve never spoken to before. There are lots of guides on writing cold emails. This one is a bit niche, as it’s about cold emailing a particular person: me. But I guarantee you that it’s the best guide you can find on this hyperspecific topic. I’m publishing my guidelines under the Creative Commons BY-4.0 license, so you’re welcome to reuse or adapt them to guide people in emailing you.
Today is the third anniversary of me quitting my job at Google to build my own software business. I posted updates at the end of my first and second years, so it’s time for another update.
A beginner-friendly tutorial for installing NixOS on a Raspberry Pi 4.
Oracle is not a very popular cloud hosting service, but they have an unusually attractive free tier offering. You can run the following two VMs for free 24/7: 4 CPU / 24 GB RAM Ampere A1 ARM VM 1 CPU / 1 GB RAM AMD CPU The AMD one is not that exciting, but a 4-CPU / 24 GB system is more powerful than you’ll find in the free tier of any other cloud vendor.
Nix is a broad product with a steep learning curve. It’s capable of everything from installing a single package to managing every file and application on your OS. One useful thing you can do with Nix, even as a complete beginner, is manage your dev environments. Nix lets me have multiple projects on the same system that each have their own independent view of what dependencies are available. I can have one legacy project running Python 2.7 and Node.js 4.x alongside a modern project running Python 3.11 and Node.js 20, and they won’t interfere with each other.
My first time raising money on Kickstarter
Four years ago today, I quit my job as a developer at Google to create my own self-funded software business. This is a review of my fourth year and what I’ve learned so far about bootstrapping software businesses.
I enjoy finding ways to exercise my rights as a consumer and push back against corporate abuse, so this was right up my alley. The book was eye-opening and made me infuriated with how corrupt the medical system is in the US and how much it extracts wealth by fleecing the middle class.
For the past few months, I’ve been working on a book called Refactoring English: Effective Writing for Software Developers. I didn’t want to spend a year writing the book only to find out that nobody wanted to buy it, so at the beginning of March, I ran a one-month pre-sale on Kickstarter. I structured the project so that if I didn’t hit $5k in pre-orders, the project would be canceled, and I’d walk away with nothing.
I just finished listening to Simon Willison’s interview on the Software Misadventures podcast. I learned a lot from the interview, so I wrote up my notes. This is not a summary of the whole interview, just the parts that were new to me or that I’d like to remember. Simon Willison on the Software Misadventures podcast Who’s Simon Willison? One of the co-creators of Django, the most popular web framework for Python. One of the most popular indepedent bloggers on Hacker News. For the last few years, has focused his blog primarily on AI, especially on applications of AI technology in everyday software development. Currently working on an open-source data analysis tool called Datasette. Plugins as a form of open-source contribution Original discussion
Revisiting David Thompson’s “My favourite Git commit”
Thinking critically about deployments.
One of my goals for the year is to learn a new programming language. It’s been a while since I learned a new language, and I feel like a lot of the languages I know well (Go, Python, C++) are similar to each other, so I want to try getting out of my comfort zone a bit with a language that feels weird to me. Requirements Here’s what I’m looking for:
How to create backup files of encrypted ZFS datasets that you can securely replicate anywhere.
I’ve purchased two AirGradient ONE indoor quality monitors to measure air quality in my home. AirGradient devices are open-source, so you can flash your own custom firmware and collect your air data locally rather than sending it to AirGradient’s proprietary cloud dashboard. I keep an AirGradient ONE air quality monitor in my office to measure CO2 and pollution. The existing documentation for flashing firmware requires you to use the Arduino IDE, a clunky GUI program:
Juggling too many half-finished tasks.
My journey to create a YouTube of memories from my family’s old home videos.
Writing short entries in a plain textbox bolstered my motivation and miraculously made status meetings interesting.
Before reading The Seven Habits of Highly Effective People, I thought of it as the canonical cliché self-help book. But as the saying goes, clichés become clichés because they’re true. The book’s insightfulness surprised me, and I found many of its ideas useful in my everyday life.
How goHardDrive exposed tens of thousands of customer records to anyone with a web browser.
Perhaps not everyone wants to join my focus group.
While figuring out my next project, I launched a different product.
How removing a single link generated a 62% sales increase
Where is my time going? (2023 edition)
I’ve been experimenting a bit with Gleam and Elixir lately as part of my search for a new programming language. One of Gleam’s flagship features is that it can call Elixir code and libraries, but I couldn’t find any examples of how to do that. I wrote a simple example of calling an Elixir library from a Gleam project, based on my beginner’s understanding of the Gleam/Elixir/Erlang ecosystem. Install dependencies For this example, I’m using
The joy and misery of editing a video interview
How to migrate from RAIDZ1 to RAIDZ2 without a spare ZFS server or a boatload of extra disks.
How can I manage TinyPilot on 20 hours per week?
Litestream is an open-source tool that backs up SQLite databases to cloud storage in real time. I love it and use it in all of my projects. Litestream is owned by Fly.io, and they paused development on Litestream for almost two years in favor of an alternative project called LiteFS. Two weeks ago, Ben Johnson, Litestream’s creator and lead developer, announced that they were shifting focus back to Litestream and had just published a new release, 0.5.0.
Not working is harder than I expected.
I’m officially running late.
I’m a pretty humble guy, so most people aren’t aware of this extremely impressive fact about me: Raymond Chen once mentioned me on his classic Windows blog, The Old New Thing.
xkcd has an undocumented way to get images of the cartoons at double their normal resolution.
I just received $5,947 in advance sales for my first technical book, even though it’s only 25% complete, and I’m self-publishing it.
I just need to focus for one hour per day.
Using low-cost radio hardware to keep texting when there’s no phone or Internet service.
How do I stop myself from rewriting the same chapter fifty times?
How many clicks does it take to add a new VLAN to an OPNsense firewall? Nothing fancy. Just your regular, basic VLAN with its own IPv4 range. How many clicks should that take? Maybe two or three? Five if we’re real wild? Every time I add a new VLAN to OPNsense, the process feels strangely tedious, so I decided to measure exactly how many clicks it takes to add a simple VLAN to my firewall.
Where do Refactoring English readers come from?
I’m officially writing a book!
I need to stop procrastinating.
What I’ve learned in my first few hours using Gleam for a small project.
Lately, I’ve been reading articles about best practices for code reviews. I notice that these articles focus on finding bugs to the exclusion of almost every…
It’s now been seven years since I quit my job at Google to become an indie founder. In the past year, I sold my company, started a family, and learned several new technologies.
Six years ago, I quit my job as a developer at Google to create my own self-funded software business. This is a review of my last year and what I’ve learned so far about bootstrapping software businesses.
I recently claimed a rebate for an EV charger, only to discover that Eversource, my power supplier, was publicly exposing personal information of customers who applied.
I’m not sure why you’d want to, but you can.
I tried out the Cline AI assistant yesterday, and then I went into a trance for five hours where I couldn’t do anything but stare transfixed at Cline fixing bugs for me. As a professional developer, it was both enchanting and terrifying. It’s enchanting that AI has reached this level of proficiency. It’s terrifying for the same reason, as I’m not sure what role I’ll serve in a world where AI can write code better and faster than I can.
Getting distracted while writing about focus
Discovering the power of AI sandboxes
I have a son!
Instead of swinging for the fences, what if I bunt?
Close to the finish line
Fuzz testing is a technique for automatically uncovering bugs in software. The problem is that it’s a pain to set up. Read any fuzz testing tutorial, and the first task is an hour of building tools from source and chasing down dependencies upon dependencies. I recently found that Nix eliminates a lot of the gruntwork from fuzz testing. I created a Nix configuration that kicks off a fuzz testing workflow with a single command. The only dependencies are Nix and git.
Fine, then I’ll just make my own app for sharing baby photos.
Exactly one year ago, I quit my job at Google, so it’s time to reflect on how the decision has affected my finances, lifestyle, and happiness.
Should I focus on my book or chase bug bounties?
This book was thoroughly underwhelming. Dozens of people have recommended it to me in the past couple of years, and I don’t understand the hype. It has some insightful ideas, but they’re buried under questionable advice and poor writing.
Claude Code has gotten extremely good at finding security vulnerabilities, and this is only the beginning.
For the past four years, I’ve worked as a software developer at Google. On February 1st, I quit. It was because they refused to buy me a Christmas present.
The standard techniques of good development can lead you astray if you don’t adjust them for unit tests.
In year 8, I discovered it takes longer than I think to write a book, found alignment with my business, and regained my love for life as an indie founder.
How I chose parts, built, and configured my first custom home storage server.
Four years after starting TinyPilot from scratch, I’ve sold the company and handed complete control over to a new owner.
I’ve published my first book chapter.
Should I be writing a book during an AI revolution?
My takeaways from selling TinyPilot
It’s surprisingly easy to hire a blog editor, and it provides tremendous value.
The brilliant relationship tip you won’t find anywhere else.
What I learned building a rack for my home server infrastructure.