On Writing Software for Yourself
There is a particular satisfaction in writing software that only you will use. The constraints are different. You don't need to handle every edge case or write documentation for a team. You can make assumptions. You can be opinionated in ways that would be irresponsible in shared code.
I've been thinking about this while building the server that runs this blog. It's a single Go file. No database, no CSS framework, no build step. Markdown files on disk, served as HTML. The entire thing fits in my head, and that's the point.
The right amount of abstraction
When you're the only user, you can skip the abstraction layer. You don't need a plugin system. You don't need configuration files. You can hardcode the port number because you know where it runs. This isn't laziness — it's precision. Every abstraction you skip is a surface area you don't have to maintain.
The fmt.Sprintf calls that generate HTML in this blog are a good example. A template engine would be "better engineering," but for three HTML shapes that rarely change, string formatting is honest work.
The best tool is the one that disappears. You stop thinking about it and start thinking about the thing you're making.
What changes when you're the audience
You become more willing to experiment. If something breaks, the blast radius is your own afternoon. You can rewrite the whole thing on a Saturday and lose nothing but time. This freedom is underrated.
There's also a directness to it. No product review, no design committee, no sprint planning. You see a thing that annoys you and you fix it. The feedback loop is instant: irritation, solution, satisfaction.
The economics of small software
Small software has different economics than big software. The cost of maintenance is nearly zero when the codebase fits in a single file. There are no dependency updates to chase, no security advisories for frameworks you forgot you installed. The attack surface is the standard library and your own code.
This blog server is about 500 lines of Go. It handles:
- Serving markdown files as HTML
- A simple archive with year/month navigation
- JSON Feed generation
- A publish workflow that watches a directory
- An in-memory cache with mtime-based invalidation
That's not nothing. But it's also not much. And "not much" is a feature when you're the one keeping it running.
A note on longevity
Go binaries are statically linked. The server I compiled today will run the same way in five years, on the same Linux kernel, without touching a package manager. Try saying that about a Node.js application.
I think about longevity more than most developers probably should. But when you're building for yourself, you're also building for future you, and future you has better things to do than debug a broken build pipeline.