The Literate Self-Hoster
There's an old idea, one which never took hold in any serious way, called "literate programming," that nonetheless has been discussed at some length over the years. The idea is that code should be more prose than code, and that reading a codebase should feel like reading a piece of literature. Now that the industry is more mature, the general consenus is that this is not a realistic way to write software.
Nonetheless, for fun and science I have been running my own experiment with the literate style over the last few years, as it is how I chose to organize my Emacs configuration, leveraging Org Mode and its ability to extract source code from a prose document and place it in some remote destination through a process called "tangling." This process was originally designed to enable literate programming in the original sense, and I couldn't resist the allure of applying it to my Emacs configuration. It has worked surprisingly well for me there, where my goal is to keep track of many changes to a slowly evolving complex system I maintain alone over the course of many years.
Based on this experience, I think Org Mode and the "tangling" feature offer a unique configuration management and change control technique, especially for a small operator like a self-hoster.
Certainly in an enterprise environment there is no contest against incredible tools like Kubernetes, but in a homelab environment or on a self-hoster's VPS, those tools present a lot of overhead and toil just to get up and running, and the user never benefits from the places where these tools really shine, handling enterprise-scale workloads and taking advantage of their ability to provide things like high availability.
Org Mode allows you to break up a plain text document by headings by annotating the beginning of a line with an asterisk like
* Systemd File
This header can have metadata attached, still in plaintext like
* My File
:PROPERTIES:
:header-args: :tangle ~/my-file
:END:
This :tangle
directive, which can be specified as shown here, or in a different way for the whole file1, or for each individual code block2, tells Emacs where the code block, or blocks, should be copied. If :tangle
is applied to a whole file or to a sub-tree as in this example, the source code is extracted out of the file and concatenated together, allowing the author to break up the source code into chunks of prose and code.
What is exciting, though, is that :tangle
has all of the same capabilities as TRAMP, which allows for writing to files as root like
:tangle /sudo::/etc/systemd/system/my-service.service
and on other systems with
:tangle /ssh:user@host:~/path/to/whatever
and for even more fun, these can be combined!
:tangle /ssh:user@host|sudo::/etc/systemd/system/my-service.service
This means that in a single file you can have:
- All of the configuration for a service, annotated with commentary on why you did something, checked into version control alongside all of the other related services in the repository.
- A record of when you did things thanks to
git
and because you can keep a journal under a subtree somewhere in the file with timestamps that Org-Mode understands like this one: - A record of on which systems various files have been installed, and at what location. This information is included necessarily because you have to write it into the tangle line.
- Any other related notes about what you did, where things are installed, what resources you found, etc.
And it means you can keep all of your configuration for all of your systems all in one repo.
When it's time to update the configuration for one of your services, instead of trying to remember where that file is located, you open the repository, find the configuration for the service in question within, make the change in the file, run M-x org-babel-tangle
in Emacs to install the new version of the file(s) to their destination(s), and then check in your changes and any notes.
There's no extra work, there's record keeping, and the only thing that you have to remember is where you kept the configuration repository. Thanks to git, you can keep it in a few places.
Maybe this methodology seems quaint compared to technology like Ansible or NixOS, but I think there's a novel administrative flow here that could be really powerful and ergonomic.
I wish other editors had an Org Mode!
Footnotes
Tangle the whole file by adding something like this to the top of the file:
#+PROPERTY: header-args: :tangle /ssh:user@host:/some/path/foo
Tangle an individual src block with header arguments:
#+begin_src c :tangle ~/some/path/foo // my code #+end_src