<?xml version='1.0' encoding='utf-8'?>
<?xml-stylesheet type="text/xsl" href="/sheet.xsl"?><rss version="2.0"><channel><title>Drew DeVault's blog</title><link>https://drewdevault.com</link><description>Drew DeVault's blog - Blog</description><generator>Zine -- https://zine-ssg.io</generator><language>en-US</language><lastBuildDate>Sun, 19 Apr 2026 13:01:20 +0000</lastBuildDate><item><title>Rewrote my blog with Zine</title><description>&lt;p&gt;15 years ago, on December 11th, 2010, at the bold age of 17, I wrote &lt;a href="https://web.archive.org/web/20120305160351/http://sircmpwn.blogspot.com/2010/12/everything-you-want-out-of-wp7.html" target="_blank"&gt;my first blog post&lt;/a&gt; on the wonders of the &lt;a href="https://en.wikipedia.org/wiki/Windows_Phone_7" target="_blank"&gt;Windows Phone 7&lt;/a&gt; on Blogspot. I started blogging as a kid at the behest of a family friend at Microsoft, who promised she’d make sure I would become the youngest &lt;a href="https://en.wikipedia.org/wiki/Microsoft_Most_Valuable_Professional" target="_blank"&gt;Microsoft MVP&lt;/a&gt; if I started blogging. That never came to pass, though, because as I entered adulthood and started to grow independent of my Microsoft-friendly family I quickly began down the path to the free and open source software community.&lt;/p&gt;&lt;p&gt;Early blog posts covered intriguing topics such as complaining about my parent’s internet filter, a horrible hack to “replace” the battery of a dead gameboy game, announcing my friend’s Minecraft guild had a new website (in PHP), and so on. After Blogspot, I moved to &lt;a href="https://jekyllrb.com/" target="_blank"&gt;Jekyll&lt;/a&gt; on GitHub pages, publishing &lt;a href="https://drewdevault.com/blog/You-dont-need-jQuery/"&gt;You don’t need jQuery&lt;/a&gt; in 2013. For a long time this was the oldest post on the site.&lt;/p&gt;&lt;p&gt;I’m pretty proud of my writing skills and have a solid grasp on who I am today, but the further back you go the worse my writing, ideas, values, and politics all get. I was growing up in front of the world on this blog, you know? It’s pretty embarassing to keep all of this old stuff around. But, I decided a long time ago to keep all of it up, so that people can understand where I’ve come from, and that everyone has to start somewhere.&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-1" id="fn-1-ref-1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&lt;p&gt;At some point – I’m not sure when – I switched from Jekyll to &lt;a href="https://gohugo.io/" target="_blank"&gt;Hugo&lt;/a&gt;, and I’ve stuck with it since. But lately I’ve been frustrated with it. I’d like my blog engine to remain relatively stable and simple, but Hugo is quite complex and over the past few years I’ve been bitten by a number of annoying and backwards-incompatible changes. And, as part of my efforts to remove vibe-coded software from my stack, I was disappointed to learn that &lt;a href="https://github.com/gohugoio/hugo/blob/842d8f105256c5656e7895ee61fa5b2dfe90a9e3/AGENTS.md" target="_blank"&gt;Hugo is being vibe coded now&lt;/a&gt;, and so rewriting my blog went onto the todo list.&lt;/p&gt;&lt;p&gt;Choosing the right static site generator (SSG) was a bit of a frustrating process. Other leading candidates, like Pelican or Zola, are also built from slop now. But a few months ago I found &lt;a href="https://zine-ssg.io/" target="_blank"&gt;Zine&lt;/a&gt;, and after further study I found it to be a pretty promising approach. Over the past few days I have rewritten my templates and ported in nearly 400 (jeesh) blog posts from my archives.&lt;/p&gt;&lt;p&gt;There’s a lot to like about Zine. I’m pretty intrigued by SuperHTML as a templating engine design – the templates are all valid HTML5 and use an interesting approach to conditions, loops, and interpolation. SuperMD has some interesting ideas, but I’m less sold on it. The Scripty language used for interpolation and logic is a bit iffy in terms of design – feels half baked. And the designers had some fun ideas, like &lt;a href="https://zine-ssg.io/log/" target="_blank"&gt;devlogs&lt;/a&gt;, which I feel are kind of interesting but tend to have an outsized influence on the design, more polished where the polish might have been better spent elsewhere. The development web server tends to hang fairly often and I’ve gotten it to crash with esoteric error messages every now and then.&lt;/p&gt;&lt;p&gt;But what can I say, it’s alpha software – I hope it will improve, and I’m betting that it will by migrating my blog. There’s no official LLM policy (&lt;a href="https://github.com/kristoff-it/zine/issues/200" target="_blank"&gt;yet&lt;/a&gt;) and I hope they will end up &lt;a href="https://github.com/kristoff-it/zine/issues/199" target="_blank"&gt;migrating to Codeberg&lt;/a&gt;, and using Discord for project communication is &lt;a href="https://drewdevault.com/blog/Dont-use-Discord-for-FOSS/"&gt;not something I appreciate&lt;/a&gt;, but maybe they’ll change their tune eventually.&lt;/p&gt;&lt;p&gt;In the meantime, I took the opportunity to clean up the code a bit. The canonical links have gone through several rounds of convention and backwards compatibility, and I have replaced them with a consistent theme and set up redirects. I probably broke everyone’s feed readers when rolling these changes out, and I apologise for that. I have gone through the backlog and updated a number of posts as best as I can to account for bitrot, but there are still a lot of broken videos and links when you get far enough back – hopefully I can restore some of that given enough time.&lt;/p&gt;&lt;p&gt;I’ve also gone ahead and imported the &lt;em&gt;really old&lt;/em&gt; stuff from Blogspot. The whole lot is garbage, but if you’re curious to see where I started out, these old posts are more accessible now.&lt;/p&gt;</description><link>https://drewdevault.com/blog/Rewrite-with-zine/</link><pubDate>Sun, 19 Apr 2026 00:00:00 +0000</pubDate><guid>https://drewdevault.com/blog/Rewrite-with-zine/</guid><ns0:encoded xmlns:ns0="http://purl.org/rss/1.0/modules/content/">&lt;article morss_own_score="6.360824742268041" morss_score="34.627036111878695"&gt;
&lt;p&gt;15 years ago, on December 11th, 2010, at the bold age of 17, I wrote &lt;a href="https://web.archive.org/web/20120305160351/http://sircmpwn.blogspot.com/2010/12/everything-you-want-out-of-wp7.html"&gt;my first blog post&lt;/a&gt; on the wonders of the &lt;a href="https://en.wikipedia.org/wiki/Windows_Phone_7"&gt;Windows Phone 7&lt;/a&gt; on Blogspot. I started blogging as a kid at the behest of a family friend at Microsoft, who promised she’d make sure I would become the youngest &lt;a href="https://en.wikipedia.org/wiki/Microsoft_Most_Valuable_Professional"&gt;Microsoft MVP&lt;/a&gt; if I started blogging. That never came to pass, though, because as I entered adulthood and started to grow independent of my Microsoft-friendly family I quickly began down the path to the free and open source software community.&lt;/p&gt;&lt;p&gt;Early blog posts covered intriguing topics such as complaining about my parent’s internet filter, a horrible hack to “replace” the battery of a dead gameboy game, announcing my friend’s Minecraft guild had a new website (in PHP), and so on. After Blogspot, I moved to &lt;a href="https://jekyllrb.com/"&gt;Jekyll&lt;/a&gt; on GitHub pages, publishing &lt;a href="https://drewdevault.com/blog/You-dont-need-jQuery/"&gt;You don’t need jQuery&lt;/a&gt; in 2013. For a long time this was the oldest post on the site.&lt;/p&gt;&lt;p&gt;I’m pretty proud of my writing skills and have a solid grasp on who I am today, but the further back you go the worse my writing, ideas, values, and politics all get. I was growing up in front of the world on this blog, you know? It’s pretty embarassing to keep all of this old stuff around. But, I decided a long time ago to keep all of it up, so that people can understand where I’ve come from, and that everyone has to start somewhere.&lt;sup&gt;&lt;a href="https://drewdevault.com/blog/Rewrite-with-zine/#fn-1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&lt;p&gt;At some point – I’m not sure when – I switched from Jekyll to &lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt;, and I’ve stuck with it since. But lately I’ve been frustrated with it. I’d like my blog engine to remain relatively stable and simple, but Hugo is quite complex and over the past few years I’ve been bitten by a number of annoying and backwards-incompatible changes. And, as part of my efforts to remove vibe-coded software from my stack, I was disappointed to learn that &lt;a href="https://github.com/gohugoio/hugo/blob/842d8f105256c5656e7895ee61fa5b2dfe90a9e3/AGENTS.md"&gt;Hugo is being vibe coded now&lt;/a&gt;, and so rewriting my blog went onto the todo list.&lt;/p&gt;&lt;p&gt;Choosing the right static site generator (SSG) was a bit of a frustrating process. Other leading candidates, like Pelican or Zola, are also built from slop now. But a few months ago I found &lt;a href="https://zine-ssg.io/"&gt;Zine&lt;/a&gt;, and after further study I found it to be a pretty promising approach. Over the past few days I have rewritten my templates and ported in nearly 400 (jeesh) blog posts from my archives.&lt;/p&gt;&lt;p&gt;There’s a lot to like about Zine. I’m pretty intrigued by SuperHTML as a templating engine design – the templates are all valid HTML5 and use an interesting approach to conditions, loops, and interpolation. SuperMD has some interesting ideas, but I’m less sold on it. The Scripty language used for interpolation and logic is a bit iffy in terms of design – feels half baked. And the designers had some fun ideas, like &lt;a href="https://zine-ssg.io/log/"&gt;devlogs&lt;/a&gt;, which I feel are kind of interesting but tend to have an outsized influence on the design, more polished where the polish might have been better spent elsewhere. The development web server tends to hang fairly often and I’ve gotten it to crash with esoteric error messages every now and then.&lt;/p&gt;&lt;p&gt;But what can I say, it’s alpha software – I hope it will improve, and I’m betting that it will by migrating my blog. There’s no official LLM policy (&lt;a href="https://github.com/kristoff-it/zine/issues/200"&gt;yet&lt;/a&gt;) and I hope they will end up &lt;a href="https://github.com/kristoff-it/zine/issues/199"&gt;migrating to Codeberg&lt;/a&gt;, and using Discord for project communication is &lt;a href="https://drewdevault.com/blog/Dont-use-Discord-for-FOSS/"&gt;not something I appreciate&lt;/a&gt;, but maybe they’ll change their tune eventually.&lt;/p&gt;&lt;p&gt;In the meantime, I took the opportunity to clean up the code a bit. The canonical links have gone through several rounds of convention and backwards compatibility, and I have replaced them with a consistent theme and set up redirects. I probably broke everyone’s feed readers when rolling these changes out, and I apologise for that. I have gone through the backlog and updated a number of posts as best as I can to account for bitrot, but there are still a lot of broken videos and links when you get far enough back – hopefully I can restore some of that given enough time.&lt;/p&gt;&lt;p&gt;I’ve also gone ahead and imported the &lt;em&gt;really old&lt;/em&gt; stuff from Blogspot. The whole lot is garbage, but if you’re curious to see where I started out, these old posts are more accessible now.&lt;/p&gt;

&lt;hr&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;And in any case I’m sure this very blog post will be a horrible embarassment to me when I stumble upon it again another 10 years hence.&lt;/p&gt;
&lt;a href="https://drewdevault.com/blog/Rewrite-with-zine/#fn-1-ref-1"&gt;Back ↩︎&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;/article&gt;
</ns0:encoded></item><item><title>🚀 Signal boost: The Future of Everything is Lies, I Guess</title><description><p>🚀 Signal boost: someone else's article that I think you should read</p><p><a href="https://aphyr.com/posts/411-the-future-of-everything-is-lies-i-guess">The Future of Everything is Lies, I Guess</a></p></description><link>https://drewdevault.com/blog/Future-of-everything-is-lies/</link><pubDate>Mon, 06 Apr 2026 00:00:00 +0000</pubDate><guid>https://drewdevault.com/blog/Future-of-everything-is-lies/</guid></item><item><title>tar: a slop-free alternative to rsync</title><description>&lt;p&gt;So apparently &lt;a href="https://codeberg.org/small-hack/open-slopware" target="_blank"&gt;rsync is slop&lt;/a&gt; now. When I heard, I wanted to drop a quick note on my blog to give an alternative: tar. It doesn’t do everything that rsync does, in particular identifying and skipping up-to-date files, but tar + ssh can definitely accomodate the use case of “transmit all of these files over an SSH connection to another host”.&lt;/p&gt;&lt;p&gt;Consider the following:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;tar -cz public | ssh example.org tar -C /var/www -xz
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will transfer the contents of &lt;code&gt;./public/&lt;/code&gt; to &lt;code&gt;example.org:/var/www/public/&lt;/code&gt;, preserving file ownership and permissions and so on, with gzip compression. This is roughly the equivalent of:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;rsync -a public example.org:/var/www/
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here’s the same thing with a lightweight progress display thanks to &lt;a href="https://ivarch.com/programs/pv.shtml" target="_blank"&gt;pv&lt;/a&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;tar -cz public | pv | ssh example.org tar -C /var/www -xz
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I know tar is infamously difficult to remember how to use. Honestly, I kind of feel that way about rsync, too. But, here’s a refresher on the most important options for this use-case. To use tar, pick one of the following modes with the command line flags:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;-c&lt;/code&gt;: create an archive&lt;/li&gt;&lt;li&gt;&lt;code&gt;-x&lt;/code&gt;: extract an archive&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Use &lt;code&gt;-f &amp;lt;filename&amp;gt;&lt;/code&gt; to read from or write to a file. Without this option, tar uses stdin and stdout, which is what the pipelines above rely on. Use &lt;code&gt;-C &amp;lt;path&amp;gt;&lt;/code&gt; to change directories before archiving or extracting files. Use &lt;code&gt;-z&lt;/code&gt; to compress or decompress the tarball with gzip. That’s basically everything you need to know about tar to use it for this purpose (and for most purposes, really).&lt;/p&gt;&lt;p&gt;With rsync, to control where the files end up you have to memorize some rules about things like whether or not each path has a trailing slash. With tar, the rules are, in my opinion, a bit easier to reason about. The paths which appear on the command line of &lt;code&gt;tar -c&lt;/code&gt; are the paths that &lt;code&gt;tar -x&lt;/code&gt; will open to create those files. So if you run this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;tar -c public/index.html public/index.css
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You get a tarball which has &lt;code&gt;public/index.html&lt;/code&gt; and &lt;code&gt;public/index.css&lt;/code&gt; in it.&lt;/p&gt;&lt;p&gt;When &lt;code&gt;tar -x&lt;/code&gt; opens this tarball, it will call &lt;code&gt;fopen(&amp;quot;public/index.html&amp;quot;, &amp;quot;w&amp;quot;)&lt;/code&gt;. So, whatever tar’s working directory is, it will extract this file into &lt;code&gt;./public/index.html&lt;/code&gt;. You can change the working directory before tar does this, on either end, by passing &lt;code&gt;tar -C &amp;lt;path&amp;gt;&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Of course, you could just use scp, but this fits into my brain better.&lt;/p&gt;&lt;p&gt;I hope that’s useful to you!&lt;/p&gt;&lt;hr&gt;&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: As a fun little challenge I wrapped up this concept in a small program that makes it easier to use:&lt;/p&gt;&lt;p&gt;&lt;a href="https://git.sr.ht/~sircmpwn/xtar" target="_blank"&gt;https://git.sr.ht/~sircmpwn/xtar&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Example:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;xtar -R /var/www me@example.org public/*
&lt;/code&gt;&lt;/pre&gt;</description><link>https://drewdevault.com/blog/rsync-without-rsync/</link><pubDate>Sat, 28 Mar 2026 00:00:00 +0000</pubDate><guid>https://drewdevault.com/blog/rsync-without-rsync/</guid><ns0:encoded xmlns:ns0="http://purl.org/rss/1.0/modules/content/">&lt;body id="body" morss_own_score="5.231121281464531" morss_score="7.6638637215062415"&gt;
&lt;h1&gt;
		tar: a slop-free alternative to rsync
		&lt;small&gt;
&lt;span&gt;March 28, 2026&lt;/span&gt;
			on
			
&lt;a href="https://drewdevault.com/"&gt;Drew DeVault's blog&lt;/a&gt;

&lt;/small&gt;
&lt;/h1&gt;
&lt;main morss_own_score="2.7226277372262775" morss_score="6.065520505306078"&gt;
&lt;article morss_own_score="6.685785536159601" morss_score="55.39411886949293"&gt;
&lt;p morss_own_score="6.25" morss_score="6.25"&gt;So apparently &lt;a href="https://codeberg.org/small-hack/open-slopware"&gt;rsync is slop&lt;/a&gt; now. When I heard, I wanted to drop a quick note on my blog to give an alternative: tar. It doesn’t do everything that rsync does, in particular identifying and skipping up-to-date files, but tar + ssh can definitely accomodate the use case of “transmit all of these files over an SSH connection to another host”.&lt;/p&gt;&lt;p&gt;Consider the following:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;tar -cz public | ssh example.org tar -C /var/www -xz
&lt;/code&gt;&lt;/pre&gt;&lt;p morss_own_score="7.0" morss_score="7.0"&gt;This will transfer the contents of &lt;code&gt;./public/&lt;/code&gt; to &lt;code&gt;example.org:/var/www/public/&lt;/code&gt;, preserving file ownership and permissions and so on, with gzip compression. This is roughly the equivalent of:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;rsync -a public example.org:/var/www/
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here’s the same thing with a lightweight progress display thanks to &lt;a href="https://ivarch.com/programs/pv.shtml"&gt;pv&lt;/a&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;tar -cz public | pv | ssh example.org tar -C /var/www -xz
&lt;/code&gt;&lt;/pre&gt;&lt;p morss_own_score="7.0" morss_score="7.0"&gt;I know tar is infamously difficult to remember how to use. Honestly, I kind of feel that way about rsync, too. But, here’s a refresher on the most important options for this use-case. To use tar, pick one of the following modes with the command line flags:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;-c&lt;/code&gt;: create an archive&lt;/li&gt;&lt;li&gt;&lt;code&gt;-x&lt;/code&gt;: extract an archive&lt;/li&gt;&lt;/ul&gt;&lt;p morss_own_score="7.0" morss_score="7.0"&gt;Use &lt;code&gt;-f &amp;lt;filename&amp;gt;&lt;/code&gt; to read from or write to a file. Without this option, tar uses stdin and stdout, which is what the pipelines above rely on. Use &lt;code&gt;-C &amp;lt;path&amp;gt;&lt;/code&gt; to change directories before archiving or extracting files. Use &lt;code&gt;-z&lt;/code&gt; to compress or decompress the tarball with gzip. That’s basically everything you need to know about tar to use it for this purpose (and for most purposes, really).&lt;/p&gt;&lt;p morss_own_score="7.0" morss_score="7.0"&gt;With rsync, to control where the files end up you have to memorize some rules about things like whether or not each path has a trailing slash. With tar, the rules are, in my opinion, a bit easier to reason about. The paths which appear on the command line of &lt;code&gt;tar -c&lt;/code&gt; are the paths that &lt;code&gt;tar -x&lt;/code&gt; will open to create those files. So if you run this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;tar -c public/index.html public/index.css
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You get a tarball which has &lt;code&gt;public/index.html&lt;/code&gt; and &lt;code&gt;public/index.css&lt;/code&gt; in it.&lt;/p&gt;&lt;p morss_own_score="7.0" morss_score="7.0"&gt;When &lt;code&gt;tar -x&lt;/code&gt; opens this tarball, it will call &lt;code&gt;fopen("public/index.html", "w")&lt;/code&gt;. So, whatever tar’s working directory is, it will extract this file into &lt;code&gt;./public/index.html&lt;/code&gt;. You can change the working directory before tar does this, on either end, by passing &lt;code&gt;tar -C &amp;lt;path&amp;gt;&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Of course, you could just use scp, but this fits into my brain better.&lt;/p&gt;&lt;p&gt;I hope that’s useful to you!&lt;/p&gt;&lt;hr&gt;&lt;p morss_own_score="5.0" morss_score="7.0"&gt;&lt;strong&gt;Update&lt;/strong&gt;: As a fun little challenge I wrapped up this concept in a small program that makes it easier to use:&lt;/p&gt;&lt;p&gt;&lt;a href="https://git.sr.ht/~sircmpwn/xtar"&gt;https://git.sr.ht/~sircmpwn/xtar&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Example:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;xtar -R /var/www me@example.org public/*
&lt;/code&gt;&lt;/pre&gt;

&lt;/article&gt;
&lt;nav&gt;

&lt;a href="https://drewdevault.com/blog/Forking-vim/"&gt;
					← A eulogy for Vim
				&lt;/a&gt;


&lt;a href="https://drewdevault.com/blog/Future-of-everything-is-lies/"&gt;
					The Future of Everything is Lies, I Guess →
				&lt;/a&gt;

&lt;/nav&gt;
&lt;/main&gt;
&lt;/body&gt;
</ns0:encoded></item><item><title>A eulogy for Vim</title><description>&lt;p&gt;Vim is important to me. I’m using it to write the words you’re reading right now. In fact, almost every word I have ever committed to posterity, through this blog, in my code, all of the docs I’ve written, emails I’ve sent, and more, almost all of it has passed through Vim.&lt;/p&gt;&lt;p&gt;My relationship with the software is intimate, almost as if it were an extra limb. I don’t think about what I’m doing when I use it. All of Vim’s modes and keybindings are deeply ingrained in my muscle memory. Using it just feels like my thoughts flowing from my head, into my fingers, into a Vim-shaped extension of my body, and out into the world. The unique and profound nature of my relationship with this software is not lost on me.&lt;/p&gt;&lt;p&gt;&lt;figure&gt;&lt;img src="https://redacted.moe/f/66af7169.jpg"&gt;
&lt;figcaption&gt;A picture of my right hand, with the letters “hjkl” tattooed on the wrist&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;&lt;p&gt;I didn’t know Bram Moolenaar. We never met, nor exchanged correspondence. But, after I moved to the Netherlands, Bram’s home country, in a strange way I felt a little bit closer to him. He passed away a couple of years after I moved here, and his funeral was held not far from where I lived at the time. When that happened, I experienced an odd kind of mourning. He was still young, and he had affected my own life profoundly. He was a stranger, and I never got to thank him.&lt;/p&gt;&lt;p&gt;The people he entrusted Vim to were not strangers, they knew Bram and worked with him often, and he trusted them. It’s not my place to judge their work as disrespectful to his memory, or out of line with what he would have wanted. Even knowing Bram only through Vim, I know he and I disagreed often. However, the most personal thing I know about Bram, and that many people remember about him, was his altruistic commitment to a single cause: providing education and healthcare to Ugandan children in need. So, at the very least, I know that he cared.&lt;/p&gt;&lt;p&gt;I won’t speculate on how he would have felt about generative AI, but I can say that GenAI is something I care about. It causes a lot of problems for a lot of people. It drives rising energy prices in poor communities, disrupts wildlife and fresh water supplies, increases pollution, and stresses global supply chains. It re-enforces the horrible, dangerous working conditions that miners in many African countries are enduring to supply rare metals like Cobalt for the billions of new chips that this boom demands. And at a moment when the climate demands immediate action to reduce our footprint on this planet, the AI boom is driving data centers to consume a full 1.5% of the world’s total energy production in order to eliminate jobs and replace them with a robot that lies.&lt;/p&gt;&lt;p&gt;Meanwhile, this whole circus is enabling the rising tide of fascism around the world, not only by supercharging propaganda but also by directly financially supporting fascist policies and policymakers.  All this to enrich the few, centralize power, reduce competition, and underwrite an enormous bubble that, once it bursts, will ruin the lives of millions of the world’s poor and marginalized classes.&lt;/p&gt;&lt;p&gt;I don’t think it’s &lt;em&gt;cute&lt;/em&gt; that someone &lt;a href="https://www.vim.org/vim-9.2-released.php#:~:text=The%20maturity,Copilot" target="_blank"&gt;vibe coded “battleship” in VimScript&lt;/a&gt;. I think it’s more important that we stop collectively pretending that we don’t understand how awful all of this is. I don’t want to use software which has slop in it. I do what I can to avoid it, and sadly even Vim now comes under scrutiny in that effort as both &lt;a href="https://github.com/vim/vim/issues/18800#issuecomment-3568099543" target="_blank"&gt;Vim&lt;/a&gt; and &lt;a href="https://github.com/neovim/neovim/pulls?q=label%3A%22AI%20assisted%20%F0%9F%A4%96%22" target="_blank"&gt;NeoVim&lt;/a&gt; are relying on LLMs to develop the software.&lt;/p&gt;&lt;p&gt;So this is how, a few years after Bram’s passing, I find myself in another unusual moment of mourning: mourning Vim itself. What an odd feeling.&lt;/p&gt;&lt;hr&gt;&lt;p&gt;To keep my conscience clear, and continue to enjoy the relationship I have with this amazing piece of software, I have forked Vim. You can find my fork here: &lt;a href="https://sr.ht/~sircmpwn/vim-classic/" target="_blank"&gt;Vim Classic&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;The choice of which version to use as the basis for a fork was a bit difficult. The last version of Vim released during Bram’s lifetime was Vim 9.0. To me, that seems like a good starting point. But, in the end, I chose to base my fork on Vim 8.2.0148 instead. Patch 148 was the patch immediately prior to the introduction of Vim9 Script, Vim 9.0’s flagship feature.&lt;/p&gt;&lt;p&gt;I’m sure Bram worked hard on Vim9 script, and I want to honor that. At the same time, it was still very new when he passed away, and the job of fully realizing its potential was handed down to the current maintainers. Its absence from Vim Classic is an honest assessment that I don’t have the time or energy to try to sort out all of the work on Vim9 which followed in Bram’s footsteps, and decide what stays and what goes. It seems like a useful line to draw in the sand: Vim Classic is compatible with legacy plugins, but not the newfangled stuff.&lt;/p&gt;&lt;p&gt;Since forking from this base, I have backported a handful of patches, most of which address CVEs discovered after this release, but others which address minor bug fixes. I also penned a handful of original patches which bring the codebase from this time up to snuff for building it on newer toolchains. My old vimrc &lt;a href="https://paste.sr.ht/~sircmpwn/bf58300e4b11542b17eeece9a3671656172f86c8" target="_blank"&gt;needed very few changes&lt;/a&gt; to work on this version of Vim, and all of my plugins work &lt;del&gt;with the exception of fzf.vim, which I would like to fix at some point (or maybe a sympathetic reader is willing to work on backporting the necessary changes)&lt;/del&gt;. &lt;em&gt;Thanks, dzwdz, for figuring out the issues with fzf.vim!&lt;/em&gt;&lt;/p&gt;&lt;p&gt;I plan to use this for a little while, look for sore points and rough edges, collect feedback from other users, and then tag a little release soon. Going forward, maintenance will be slow and quiet. I welcome your patches, particularly to help with maintaining the runtime scripts, stuff like making sure new language features end up in the syntax files. I’ll also gladly accept new bug fixes, and maybe even a few new features if a good case can be made for including them. Backporting small patches from Vim upstream will be considered, with extra scrutiny.&lt;/p&gt;&lt;p&gt;In short, I invite you to use Vim Classic, if you feel the same way as me, and to maintain it with me, contributing the patches you need to support your own use cases.&lt;/p&gt;</description><link>https://drewdevault.com/blog/Forking-vim/</link><pubDate>Wed, 25 Mar 2026 00:00:00 +0000</pubDate><guid>https://drewdevault.com/blog/Forking-vim/</guid><ns0:encoded xmlns:ns0="http://purl.org/rss/1.0/modules/content/">&lt;article morss_own_score="6.795833333333333" morss_score="57.19638888888889"&gt;
&lt;p&gt;Vim is important to me. I’m using it to write the words you’re reading right now. In fact, almost every word I have ever committed to posterity, through this blog, in my code, all of the docs I’ve written, emails I’ve sent, and more, almost all of it has passed through Vim.&lt;/p&gt;&lt;p&gt;My relationship with the software is intimate, almost as if it were an extra limb. I don’t think about what I’m doing when I use it. All of Vim’s modes and keybindings are deeply ingrained in my muscle memory. Using it just feels like my thoughts flowing from my head, into my fingers, into a Vim-shaped extension of my body, and out into the world. The unique and profound nature of my relationship with this software is not lost on me.&lt;/p&gt;&lt;p&gt;&lt;figure&gt;&lt;img src="https://redacted.moe/f/66af7169.jpg"&gt;
&lt;figcaption&gt;A picture of my right hand, with the letters “hjkl” tattooed on the wrist&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;&lt;p&gt;I didn’t know Bram Moolenaar. We never met, nor exchanged correspondence. But, after I moved to the Netherlands, Bram’s home country, in a strange way I felt a little bit closer to him. He passed away a couple of years after I moved here, and his funeral was held not far from where I lived at the time. When that happened, I experienced an odd kind of mourning. He was still young, and he had affected my own life profoundly. He was a stranger, and I never got to thank him.&lt;/p&gt;&lt;p&gt;The people he entrusted Vim to were not strangers, they knew Bram and worked with him often, and he trusted them. It’s not my place to judge their work as disrespectful to his memory, or out of line with what he would have wanted. Even knowing Bram only through Vim, I know he and I disagreed often. However, the most personal thing I know about Bram, and that many people remember about him, was his altruistic commitment to a single cause: providing education and healthcare to Ugandan children in need. So, at the very least, I know that he cared.&lt;/p&gt;&lt;p&gt;I won’t speculate on how he would have felt about generative AI, but I can say that GenAI is something I care about. It causes a lot of problems for a lot of people. It drives rising energy prices in poor communities, disrupts wildlife and fresh water supplies, increases pollution, and stresses global supply chains. It re-enforces the horrible, dangerous working conditions that miners in many African countries are enduring to supply rare metals like Cobalt for the billions of new chips that this boom demands. And at a moment when the climate demands immediate action to reduce our footprint on this planet, the AI boom is driving data centers to consume a full 1.5% of the world’s total energy production in order to eliminate jobs and replace them with a robot that lies.&lt;/p&gt;&lt;p&gt;Meanwhile, this whole circus is enabling the rising tide of fascism around the world, not only by supercharging propaganda but also by directly financially supporting fascist policies and policymakers.  All this to enrich the few, centralize power, reduce competition, and underwrite an enormous bubble that, once it bursts, will ruin the lives of millions of the world’s poor and marginalized classes.&lt;/p&gt;&lt;p&gt;I don’t think it’s &lt;em&gt;cute&lt;/em&gt; that someone &lt;a href="https://www.vim.org/vim-9.2-released.php#:~:text=The%20maturity,Copilot"&gt;vibe coded “battleship” in VimScript&lt;/a&gt;. I think it’s more important that we stop collectively pretending that we don’t understand how awful all of this is. I don’t want to use software which has slop in it. I do what I can to avoid it, and sadly even Vim now comes under scrutiny in that effort as both &lt;a href="https://github.com/vim/vim/issues/18800#issuecomment-3568099543"&gt;Vim&lt;/a&gt; and &lt;a href="https://github.com/neovim/neovim/pulls?q=label%3A%22AI%20assisted%20%F0%9F%A4%96%22"&gt;NeoVim&lt;/a&gt; are relying on LLMs to develop the software.&lt;/p&gt;&lt;p&gt;So this is how, a few years after Bram’s passing, I find myself in another unusual moment of mourning: mourning Vim itself. What an odd feeling.&lt;/p&gt;&lt;hr&gt;&lt;p&gt;To keep my conscience clear, and continue to enjoy the relationship I have with this amazing piece of software, I have forked Vim. You can find my fork here: &lt;a href="https://sr.ht/~sircmpwn/vim-classic/"&gt;Vim Classic&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;The choice of which version to use as the basis for a fork was a bit difficult. The last version of Vim released during Bram’s lifetime was Vim 9.0. To me, that seems like a good starting point. But, in the end, I chose to base my fork on Vim 8.2.0148 instead. Patch 148 was the patch immediately prior to the introduction of Vim9 Script, Vim 9.0’s flagship feature.&lt;/p&gt;&lt;p&gt;I’m sure Bram worked hard on Vim9 script, and I want to honor that. At the same time, it was still very new when he passed away, and the job of fully realizing its potential was handed down to the current maintainers. Its absence from Vim Classic is an honest assessment that I don’t have the time or energy to try to sort out all of the work on Vim9 which followed in Bram’s footsteps, and decide what stays and what goes. It seems like a useful line to draw in the sand: Vim Classic is compatible with legacy plugins, but not the newfangled stuff.&lt;/p&gt;&lt;p&gt;Since forking from this base, I have backported a handful of patches, most of which address CVEs discovered after this release, but others which address minor bug fixes. I also penned a handful of original patches which bring the codebase from this time up to snuff for building it on newer toolchains. My old vimrc &lt;a href="https://paste.sr.ht/~sircmpwn/bf58300e4b11542b17eeece9a3671656172f86c8"&gt;needed very few changes&lt;/a&gt; to work on this version of Vim, and all of my plugins work &lt;del&gt;with the exception of fzf.vim, which I would like to fix at some point (or maybe a sympathetic reader is willing to work on backporting the necessary changes)&lt;/del&gt;. &lt;em&gt;Thanks, dzwdz, for figuring out the issues with fzf.vim!&lt;/em&gt;&lt;/p&gt;&lt;p&gt;I plan to use this for a little while, look for sore points and rough edges, collect feedback from other users, and then tag a little release soon. Going forward, maintenance will be slow and quiet. I welcome your patches, particularly to help with maintaining the runtime scripts, stuff like making sure new language features end up in the syntax files. I’ll also gladly accept new bug fixes, and maybe even a few new features if a good case can be made for including them. Backporting small patches from Vim upstream will be considered, with extra scrutiny.&lt;/p&gt;&lt;p&gt;In short, I invite you to use Vim Classic, if you feel the same way as me, and to maintain it with me, contributing the patches you need to support your own use cases.&lt;/p&gt;

&lt;/article&gt;
</ns0:encoded></item><item><title>The cults of TDD and GenAI</title><description>&lt;p&gt;I’ve gotten a lot of flack throughout my career over my disdain towards test-driven development (TDD). I have met a lot of people who swear by it! And, I have also met a lot of people who insisted that I adopt it, too, often with the implied threat of appealing to my boss if appealing to me didn’t work.&lt;/p&gt;&lt;p&gt;The basic premise of TDD, for those unaware, is that one &lt;em&gt;first&lt;/em&gt; writes a unit test that verifies the expected behavior for some code they want to write, observes the new test fail, and &lt;em&gt;then&lt;/em&gt; one writes the implementation, iterating on it until the test passes. The advantage of this approach is, first, to ensure that your codebase is adequately covered by testing, and, second, to provide you a rapid feedback loop to assist in your work.&lt;/p&gt;&lt;p&gt;I have often found elements of TDD to be quite useful. Using a unit test or something similar to provide an efficient rapid feedback loop is a technique which I have employed many times. However, I am and have always been skeptical of the cult which arises around automated software testing and in particular TDD. A lot of people adopt an unquestioning loyalty to TDD, building tools and practices and &lt;span class="rainbow"&gt;vibes&lt;/span&gt; around the idea. It’s often too much.&lt;/p&gt;&lt;style&gt;
.rainbow {
  font-weight: bold;
  background-image: linear-gradient(to left, violet, indigo, blue, green, yellow, orange, red);
  background-clip: text;
  background-size: 800% 800%;
  animation: rainbow 8s ease infinite;
  -webkit-text-fill-color: transparent;
}

@keyframes rainbow { 
    0%{background-position:0% 50%}
    50%{background-position:100% 25%}
    100%{background-position:0% 50%}
}
&lt;/style&gt;
&lt;p&gt;The flaw with TDD is that, while it ensures that you have a test for every function you write, it also exerts an influence on the tested codebase, shaping the code to be as “testable” as possible, which only sometimes leads to better code. Moreover, TDD has no means of ensuring that the behavior that your tests verify is the &lt;em&gt;right&lt;/em&gt; behavior for your software to have. Software with a thousand passing tests and 100% test coverage could be doing whatever the user or the business or whatever needs it to, but it could just as easily not meet the requirements in spite of those comprehensive tests – and in any case it gives you confidence in your work, which may or may not be misplaced.&lt;/p&gt;&lt;p&gt;The cult of TDD exploits the fact that TDD is very good at making you feel like a good, diligent programmer. That rapid feedback loop not only assists in your work but also enables a powerful dopamine cycle. Add into that a culture of aiming for 100% coverage and you get the bonus hit from watching a number go up. Buy into the whole cult and you get a slew of new README badges to keep green, and lots of cool charts and numbers, hundreds of blinkenlights on your test suite, a bunch of fun Slack messages from Jenkins, and a cute cardboard cut-out of the CTO to keep in the cubicle of whoever last broke the build.&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-1" id="fn-1-ref-1"&gt;1&lt;/a&gt;&lt;/sup&gt; All of this pomp and circumstance is &lt;em&gt;fun&lt;/em&gt; and it feels &lt;em&gt;good&lt;/em&gt; and because it’s all in the name of testing (which is good, right?) it makes you feel like a &lt;em&gt;good programmer&lt;/em&gt; even if none of it necessarily contributes to the results your team is supposed to achieve.&lt;/p&gt;&lt;p&gt;All of these flashy traits allow one to adopt the aesthetics of good, diligent software engineering work regardless of how good the work actually is. It’s an intoxicating way to work, especially for someone who struggles with software engineering. It makes you feel like a good programmer and gives you data to “back it up”, stuff you can cite at your performance review. But, software development is really hard, and TDD doesn’t go that far to making it easier. All of the really hard problems are not solved by TDD.&lt;/p&gt;&lt;p&gt;I suspect that coding agents are tapping into the same emotional and psychological reflexes that the cult of TDD gives us an early example of. Software development is still hard, but using an agent allows someone who’s just “so-so” at programming to feel the rush of being great at programming, a rush they might have been chasing for their entire career, and I bet the rush is so much sweeter than watching the lights on your test suite runs tick over to green.&lt;/p&gt;&lt;p&gt;A coding agent permits one to feel as if they have the raw productive power a great programmer can tap into. One may feel like the “10× programmers” they’ve sat next to in the open office for ten years, whose skills they never quite achieved themselves. It scales up the raw output by a factor of ten, and lets one assemble apparently great works in a fraction of the time, solo-coding great cathedrals in the time it used to take them to build, with great difficulty, a homely shack.&lt;/p&gt;&lt;p&gt;But, if it seems too good to be true…&lt;/p&gt;&lt;p&gt;Those cathedrals are not the great works they appear to be. The construction is shoddy and the architecture nonsensical and a great programmer hand-writing code will still outperform any mediocre programmer once the gleam wears off of their respective works and the bugs and problems start showing up. The project has 99.9% coverage on a thousand beautiful green tests, and, inside, the foundations are still rotten.&lt;/p&gt;&lt;p&gt;God, though, I understand why so many people are chasing that dragon, even though it’s going to ruin their careers, and maybe even their lives. I get why people fall for this, in spite of the externalities that they must know of by now. In spite of the colossal waste, the loss of fresh water resources, the fact that AI datacenters are the fastest growing source of carbon emissions, the people suffering sky-rocketing power bill and rolling outages near these new datacenters, the reams and reams of fascist propaganda these machines are producing to tear our society apart, the corruption, the market manipulation, the plain and simple fact that the ultimate purpose of these tools is to put their users &lt;em&gt;out of a job entirely&lt;/em&gt;… well, once you finally get a taste of what it feels like to be &lt;em&gt;great&lt;/em&gt;… I suppose all of those problems seem so far away.&lt;/p&gt;</description><link>https://drewdevault.com/blog/Cult-of-TDD-and-LLMs/</link><pubDate>Thu, 29 Jan 2026 00:00:00 +0000</pubDate><guid>https://drewdevault.com/blog/Cult-of-TDD-and-LLMs/</guid><ns0:encoded xmlns:ns0="http://purl.org/rss/1.0/modules/content/">&lt;article morss_own_score="6.971134020618557" morss_score="43.92183824597067"&gt;
&lt;p&gt;I’ve gotten a lot of flack throughout my career over my disdain towards test-driven development (TDD). I have met a lot of people who swear by it! And, I have also met a lot of people who insisted that I adopt it, too, often with the implied threat of appealing to my boss if appealing to me didn’t work.&lt;/p&gt;&lt;p&gt;The basic premise of TDD, for those unaware, is that one &lt;em&gt;first&lt;/em&gt; writes a unit test that verifies the expected behavior for some code they want to write, observes the new test fail, and &lt;em&gt;then&lt;/em&gt; one writes the implementation, iterating on it until the test passes. The advantage of this approach is, first, to ensure that your codebase is adequately covered by testing, and, second, to provide you a rapid feedback loop to assist in your work.&lt;/p&gt;&lt;p&gt;I have often found elements of TDD to be quite useful. Using a unit test or something similar to provide an efficient rapid feedback loop is a technique which I have employed many times. However, I am and have always been skeptical of the cult which arises around automated software testing and in particular TDD. A lot of people adopt an unquestioning loyalty to TDD, building tools and practices and &lt;span&gt;vibes&lt;/span&gt; around the idea. It’s often too much.&lt;/p&gt;&lt;p&gt;The flaw with TDD is that, while it ensures that you have a test for every function you write, it also exerts an influence on the tested codebase, shaping the code to be as “testable” as possible, which only sometimes leads to better code. Moreover, TDD has no means of ensuring that the behavior that your tests verify is the &lt;em&gt;right&lt;/em&gt; behavior for your software to have. Software with a thousand passing tests and 100% test coverage could be doing whatever the user or the business or whatever needs it to, but it could just as easily not meet the requirements in spite of those comprehensive tests – and in any case it gives you confidence in your work, which may or may not be misplaced.&lt;/p&gt;&lt;p&gt;The cult of TDD exploits the fact that TDD is very good at making you feel like a good, diligent programmer. That rapid feedback loop not only assists in your work but also enables a powerful dopamine cycle. Add into that a culture of aiming for 100% coverage and you get the bonus hit from watching a number go up. Buy into the whole cult and you get a slew of new README badges to keep green, and lots of cool charts and numbers, hundreds of blinkenlights on your test suite, a bunch of fun Slack messages from Jenkins, and a cute cardboard cut-out of the CTO to keep in the cubicle of whoever last broke the build.&lt;sup&gt;&lt;a href="https://drewdevault.com/blog/Cult-of-TDD-and-LLMs/#fn-1"&gt;1&lt;/a&gt;&lt;/sup&gt; All of this pomp and circumstance is &lt;em&gt;fun&lt;/em&gt; and it feels &lt;em&gt;good&lt;/em&gt; and because it’s all in the name of testing (which is good, right?) it makes you feel like a &lt;em&gt;good programmer&lt;/em&gt; even if none of it necessarily contributes to the results your team is supposed to achieve.&lt;/p&gt;&lt;p&gt;All of these flashy traits allow one to adopt the aesthetics of good, diligent software engineering work regardless of how good the work actually is. It’s an intoxicating way to work, especially for someone who struggles with software engineering. It makes you feel like a good programmer and gives you data to “back it up”, stuff you can cite at your performance review. But, software development is really hard, and TDD doesn’t go that far to making it easier. All of the really hard problems are not solved by TDD.&lt;/p&gt;&lt;p&gt;I suspect that coding agents are tapping into the same emotional and psychological reflexes that the cult of TDD gives us an early example of. Software development is still hard, but using an agent allows someone who’s just “so-so” at programming to feel the rush of being great at programming, a rush they might have been chasing for their entire career, and I bet the rush is so much sweeter than watching the lights on your test suite runs tick over to green.&lt;/p&gt;&lt;p&gt;A coding agent permits one to feel as if they have the raw productive power a great programmer can tap into. One may feel like the “10× programmers” they’ve sat next to in the open office for ten years, whose skills they never quite achieved themselves. It scales up the raw output by a factor of ten, and lets one assemble apparently great works in a fraction of the time, solo-coding great cathedrals in the time it used to take them to build, with great difficulty, a homely shack.&lt;/p&gt;&lt;p&gt;But, if it seems too good to be true…&lt;/p&gt;&lt;p&gt;Those cathedrals are not the great works they appear to be. The construction is shoddy and the architecture nonsensical and a great programmer hand-writing code will still outperform any mediocre programmer once the gleam wears off of their respective works and the bugs and problems start showing up. The project has 99.9% coverage on a thousand beautiful green tests, and, inside, the foundations are still rotten.&lt;/p&gt;&lt;p&gt;God, though, I understand why so many people are chasing that dragon, even though it’s going to ruin their careers, and maybe even their lives. I get why people fall for this, in spite of the externalities that they must know of by now. In spite of the colossal waste, the loss of fresh water resources, the fact that AI datacenters are the fastest growing source of carbon emissions, the people suffering sky-rocketing power bill and rolling outages near these new datacenters, the reams and reams of fascist propaganda these machines are producing to tear our society apart, the corruption, the market manipulation, the plain and simple fact that the ultimate purpose of these tools is to put their users &lt;em&gt;out of a job entirely&lt;/em&gt;… well, once you finally get a taste of what it feels like to be &lt;em&gt;great&lt;/em&gt;… I suppose all of those problems seem so far away.&lt;/p&gt;

&lt;hr&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;That actually happened at one of my old jobs.&lt;/p&gt;
&lt;a href="https://drewdevault.com/blog/Cult-of-TDD-and-LLMs/#fn-1-ref-1"&gt;Back ↩︎&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;/article&gt;
</ns0:encoded></item></channel></rss>