May 30, 2021

I don’t expect that anyone reads this blog. It exists because I wanted to write the software for it. More specifically, I wanted to write a Golang app, using GraphQL and a typical React-style Javascript administrative interface. Another goal was to have the blog itself rendered via templates on the server, rather than dynamically in the browser. Finally, use good old Postgres to store the data. All of this flies in the face of the then (and maybe still current) fashion for statically generated web sites, which I still think is a good idea, fashionable or not. On top of all that, I wanted to develop the code on macOS, and deploy on FreeBSD. All of that worked out fine.

In the end, I wouldn’t make these same choices, even if I kept the basic underlying goal of developing a database backed, templated, single-page-client-app blog engine.

First, Postgres. I love the database and it hasn’t been an issue for me almost at all, though over the years I have to update it and in doing so, the database can become incompatible. You have to run special scripts, or export/import to move to the next point release of Postgres. This is a better fit for a production-oriented web infrastructure, not so much for a one-off blog engine. The better bet (if I want to stick with a database) is sqlite3. That’s a conditional bet. I’ve not yet experienced what its like to maintain such a file over multiple years. What I do know is that I’ve used it as the bases for Core Data persistence in macOS apps over multiple years and I’ve never needed to worry about OS upgrades.

Second, Golang. There’s lots to love about Go, from my perspective, especially these days now that they’ve improved dependencies, and don’t require you place your source code repo in a deep sub-directory based on your domain, and/or the domain of your Github account. The standard library is excellent, at least for any of the server-side things I’m likely to use it for. The problem, for me, and for so many others, is the lack of generics. After using both Rust and Swift, I feel like having to write separate functions for every single data type is not for me. Either give me a dynamic language, or give me something with sufficiently sophisticated types that I can write code as if I were writing in a dynamic language.

Third, GraphQL. On the one hand, I really appreciate that GraphQL has broken the back of REST as an orthodoxy. REST makes sense for some use cases, but it’s unfriendly for rich client development. The real breakthrough (or umpteenth re-invention) is the idea of the query and a query language. Post a query, get tailored results back, let the server do all the complicated joins. GraphQL is one way to do this. Salesforce provides SOSL, which looks like SQL with graph features built in. For me, though, I think I could get away with something way simpler: JSON/HTTP. That’s right, just some non-REST-orthodox queries. For that admin interface, I need a list of posts, and I need a single post. That part can be REST. For updating posts, changing dates, titles, updating passwords and accounts, I can use a single endpoint and POST a command to it. This is similar to the pattern found in GraphQL (query vs mutate), but much simpler to implement. The key is that I’m not developing a set of rich clients for use across a variety of presentation devices. I’m not twenty separate teams each of which need some slightly different view of the data depending on local conditions. Not only is GraphQL overkill in my own case, I suspect it’s overkill for a lot of cases where people use it today. It’s fashionable, has mindshare, can settle arguments inside corporate tech groups, but it’s not often appropriate.

Fourth, React/Javascript. Remember the olden times when you could type Javascript into a file, refresh the browser, and see the changes? Well, those days are still here. I’ve done recent work on a project that still uses a page-based architecture with jQuery built in whether you want it or not and, well, it’s fine. It’s still fine. It actually works quite well, in fact. Wasn’t React a framework that made it easier to inject little components into an otherwise normal web page? And now it’s a complete stack with convenience plugins for all the things it was never intended to use. Beneath that, we’ve got web-pack, all kinds of ecmascript transliteration strategies, dynamic lazy loading strategies, massive dependency graphs, multiple package managers (from declarative to Turing-complete), and on and on. We’ve turned that simple refresh-the-browser mode into something as deeply complicated as Enterprise Java turned out to be. Finally, we’ve got a vast syntactic expansion of the language into classes, anonymous functions, an odd literal map/list interpolation “associate” style mutation syntax, and on and on. Javascript is not easy to read, anymore, depending on how old the codebase is. It’s not like reading the Rosetta stone: three distinct language saying the same thing, its more like reading a single document, parts of which are written in archaic Greek, then ancient Greek, koine Greek, modern Greek, and non-native Slavic attempts at Greek. You can put it all together, but the satisfaction is in your cleverness, not in the content. I’m not sure about this, but I think current React requires you to use transliteration software because it’s based on Javascript classes which aren’t compatible, somehow, with standard browsers. And then there’s the Cambrian explosion of module strategies….

Let me turn down the crankiness a bit, though, and say that this is okay. Unless you’re trapped on a corporate team that made a tech choice in a given year such that you’re condemned to live with it for the rest of your time in that job, this React/Redux/Javascript toolchain is just another tech choice you can make. Or not make. The thing I didn’t anticipate years ago (just to see what it was like) were the massive amounts of dependencies of dependencies of dependencies, something of an industry, what-are-you-gonna-do joke. Being able to depend on the code of a lot of other people is a strength, but I think most of that strength happens at the project bootstrap stage. After that, you’re constantly updating those dependencies against the number vulnerabilities discovered month after month. Generally no big deal (unless you have to constantly cajole product/project/agility managers to let you do it), but each update requires a retest of your application as React and other core tech update over time, not to mention the fact that the browsers themselves (the environment in which these applications run) evolve over time, too. If you’re inclined to think that maybe React was designed by Facebook in order to slow down and overburden other web-app companies, you might be hard pressed to resist. It’s not even Facebook’s issue: it’s our tendency as developers to go all in, to confuse technology with architecture. If I re-do this admin interface (which also contains a tiny editor for writing or pasting in posts), I’d rewrite it in Clojurescript. The language doesn’t change (though I generally love change) in the sense that it consists of data and functions and namespaces, and that’s it. Need something new? Write a function, not a completely new syntax that needs a server-side build system to reduce back down to early-2000 era Javascript. If you want to write the application with few run-time dependencies, you can do that because you can just write the three date functions you need and be confident that the dependencies didn’t pull in multiple date-time libraries as needed for each little thing. Just include React, and do the rest yourself. (You don’t even need Redux. Clojurescript has “reducible” state functions build in.) The stability is astounding, and the satisfaction of well-made, just-what-you-need tech is maybe, at the root, why most of us still like doing this rather than joining up with WordPress. I don’t think I’d go with jQuery and a page-oriented, JSP like architecture for the Admin pages because that requires a lot of set up I just don’t want to do. But a simple Reagent based application is worth it to me, especially if I give up “REST” style paths for deep linking.

What would I do next if I wanted to re-do this project?

  • Rust lang
  • Sqlite3
  • Clojurescript Admin/Post client
  • Single query endpoint, single command endpoint

That’s it!

Well, almost.

I like hosting this on FreeBSD, which might be a problem for Rust and Sqlite3, at least in this one way: I’m not likely to be able to cross-compile the Rust server side on macOS for deployment on FreeBSD. I don’t think Rust has a pure-RUST implementation of the Sqlite3 API on macOS, for example. Maybe it will by the time I get around to doing this.