In the process of consolidating an alpha release out of the last eight months of work, I’ve had a chance to return to some earlier decisions and see how they’ve played out. I’m going to talk about two of those decisions—one good (so far) and one bad—because I think they reflect on the type of system I’m trying to build.
I just finished rewriting the code that publishes this blog. I came up with the original design around the time that I was writing posts about the REST architectural style. I was excited about the idea of a distributed system—a system with multiple independent parts that interact without necessarily having a central point of control. At that time I was still undecided about what I wanted to use as a user interface—I experimented with writing a slack bot as a way to publish posts and images to this blog—when I posted specific messages to a private slack channel, the bot would pick them up and post the content to this site. So as I was designing the system that managed the blog posts I tried to separate it into the smallest functional components I could think of, in case I wanted to reorganize it later. There was one function that knew how to render HTML, one function that knew how to match up a post with its tags (or a tag with its posts), one function that knew how to update the metadata store when a post changed, and finally a function that cleaned up HTML when a post was deleted. At the center was a file I called the site description, which each of those functions used to get the details of how it was supposed to do its job.
This felt like a good start. I liked particularly that the site description file was like a map to the whole site. I liked the feeling that each function’s job was dead simple[1], I liked that all of the site materials—the templates, the site description, some of the post metadata-lookup code—could be represented using their URLs[2]. From a technical perspective, it felt important that I’d gotten those different parts to work together—that is, it was a proof-of-concept that I could tie together functions, networking, and storage into a system like that, which I knew was going to be important. I had also explored my options for databases and validated that I could integrate one easily and cheaply. And since there were still so many unknowns, it seemed wise that I’d kept everything separate—whichever pieces ended up being important could be kept, and whichever ones didn’t could be discarded. Including learning time, it probably took at least a month, maybe two, out of the 12 I planned for this project.
But last Friday I found myself throwing out most of that work and sketching out a much simpler and more limited system in my notebook. Instead of my site description, how about no site description? Instead of four different functions, how about one? Instead of making sure every individual building block of the site had its own URL, how about not publishing anything except the site itself? Two days later, on Sunday, I had mostly finished the code and some tests. On Monday (today) I’ve deployed it successfully; it’s the only thing hosting my blog as I write this.
There are two stories here, as I said at the beginning. The first story is about missing the mark with that first blog design. The second story is about the much better decisions I made about state, which have allowed me to migrate all of my blog posts from a static site, to v1 of this site, to v2 of this site (complete with its own authoring UI!) without having to change their format, content, or where they were stored.
So what was wrong with that first design? One flaw was that it was just too spread out—each little function turned out to need many of the same things, so there was a lot of unnecessary redundancy. But overall, the problem was that it was both unfinished—most of the benefits of that design would only be valuable if the system grew much bigger than it was—and speculative—I didn’t exactly know what things I wanted to add that would take up all that extra space. It was kind of like needing to build a two-car garage next to your house, going to the big-box store in a fugue state, and only waking up days later to find that you’ve built a six-car garage in a vacant lot halfway across town. As garages go, is that better? I suspect it depends on whether you ask a garage enthusiast.
That’s not to say it was a waste of time. The second version came together so quickly because I had spent a lot of effort the first time on improving my tools and techniques[3]. And I need to try stuff out. I build models, I go down rabbit holes, I explore what turn out to be dead ends. I’m perfectly happy to have used my time that way, even when it feels frustrating. By not being mad at the me-in-the-past who tried things out, I give myself continuing permission to do so.
And as it happened, rewriting the blog gave me a chance to validate a theory I advanced a few months ago—that it is better to think of this kind of system not primarily as a mechanism, but as an archive. That is, the core of the system consists of artifacts of human attention—these blog posts as text files and images. Those files are like the trunk of a tree, and the different rendering functions, networking infrastructure, management and UI code are like the leaves of the tree—they are not permanent; they change with the seasons. This is in distinct contrast to the commercial view of internet services, where switching from one system to another means moving or losing your data. I think that this idea has been worth its weight in gold to me over this process, and it will prove to be a differentiator for this type of system.
This is the first blog post I’ve written in my browser, using my own UI. It feels good—even when my session timed out I didn’t lose any of my work. But better than that is knowing that when I click the Save button, the post comes to rest, as a text file, in the same place and in the same format as the posts I used to write in my terminal using a basic text editor. The effort that I spend today on writing this post will plausibly be available to me a year from now, when I’m using a completely different system, just as the posts I wrote a year ago, using a totally different system, are available to me through this new UI.
I said I liked this feeling; as we’ll see the reality was different. ↩︎
This is very much in the spirit of REST. ↩︎
I write most of my code in the same style (a colleague once called it a domain-specific language, though it may just be a framework) , as explicitly-structured state machines. This structure makes it fairly flexible and extremely easy to adapt to changing infrastructure configurations. A lot of the time I spent building the first blog consisted of improving that state-machine code to handle different situations I encountered. It’s like a really simple but powerful multitool that I’ve been using and improving for years now (since 2018) and it keeps getting better. ↩︎