Category Archives: Personal

Dev Stack 2025, Part VI: Bulma

This is part of a series describing how I am changing my entire stack for developing web applications. My choices are driven by security and simplicity.

In my drive for simplicity I have decided to have no build for scripts and CSS. This means I can’t use Tailwind, which I would otherwise choose.

In my research, I found a few options, and I have tentatively chosen Bulma. Aside from having no build, it’s other strength is that Copilot knows it well enough to help me use it.

I also considered Pico and Bootstrap. I preferred Bulma’s default look to Pico and I have already used Bootstrap in the past, so I basically know what to expect. I chose Bulma to see how it compares. If it falls short, I’ll move to Bootstrap. I’m pretty sure that Copilot will know it.

It’s worth saying here that if I had chosen Ruby on Rails instead of Python/Django, Hotwire would have been a sane default choice and would have played the role that HTMX and Bulma are playing for me.

Dev Stack 2025, Part V: VSCode and Copilot

This is part of a series describing how I am changing my entire stack for developing web applications. My choices are driven by security and simplicity.

I switched to Cursor in February because its prompting capabilities were way beyond Copilot. But, I’ve increasingly become frustrated with everything else about it.

Even though I use AI to generate code, I still need to fix that code myself. I also tend to do refactoring myself. So, the IDE’s regular coding features are still important to my work. Since Cursor is a fork of VSCode, moving to it was simple, but their fork is starting to age, and it doesn’t look like they can keep up with VSCode.

The first thing I noticed was that they could no longer load the latest versions of extensions I use. When I researched why, it turned out it was because they were not merging in VSCode changes any more. When 2.0 came out last week and the extensions were still stuck, I knew they didn’t share my security priorities. Not being able to update something is a huge red flag.

So, just to check, I tried out VSCode again. They could load the latest versions of extensions (of course), but I also noticed lots of little improvements to the UI. The most striking was the speed. But, also, the exact timing of auto-complete suggestions was less intrusive than Cursor. They could both use some improvement, but by default, Copilot was a little less anxious to complete, which suits me better.

But this switch would not have been possible if the prompt-based coding was worse than Cursor. So far, in the week I have been using it, I haven’t noticed a difference. They are both not perfect, but that’s fine with me.

Ten months ago, Copilot wasn’t worth using. Now, it feels the same as Cursor. I don’t know if that might also be because my prompting has improved, but it doesn’t matter. My goal is to add a CLI based agent to my stack, so I think I would close any gap that way.

In my drive to simplify and reduce dependencies, it’s also good to be able to remove a vendor. I have to rely on Microsoft already, and I trust them, so moving to just VSCode/Copilot is a plus. I was pretty sure this was going to happen.

In April, after two months on Cursor, I wrote:

The problem for Cursor in competing with Microsoft is that Microsoft has no disincentive to follow them. [… And] because Cursor is easy to switch back from, there is actually no advantage to Cursor’s land grab. I went from VSCode with Copilot to Cursor in 20 minutes, and I could go back faster. I can run them in parallel.

Here are Microsoft’s other incumbent advantages:

  1. Infinite money
  2. Azure (gives them at-cost compute)
  3. Experience with AI engineering (built up from years of working with OpenAI)
  4. The relationship with OpenAI which gives them low-cost models
  5. 50 years of proprietary code (could this augment models?)
  6. Developer Tools expertise (and no one is close — maybe JetBrains)
  7. GitHub
  8. Control of Typescript and C#
  9. Control of VSCode (which they are flexing)

In the end, #6 might not be possible for anyone else to overcome, and it’s why I’m back.

Dev Stack 2025, Part IV: HTMX

This is part of a series describing how I am changing my entire stack for developing web applications. My choices are driven by security and simplicity.

I have been a fan of server-authoritative UI since the ’90s and have worked to make it more interactive. The general idea is that there is no application code running on the client and that the server handles all events and renders updates.

Regular HTML webpages with no JavaScript are an example of this style. So are 60’s-style mainframes with dumb terminals. There are several systemic advantages to this architecture, but one big disadvantage is granular interactivity. In the past four years, I went the complete opposite way by using React and essentially building a fat-client in the browser. But, when I saw HTMX last year, I thought I could go back at some point.

That point is now.

Everything is on the table, and since I will not use NPM, it makes it harder to use React. My drive to simplicity just won’t accept the dependency footprint any more. HTMX is dependency-free. Exactly what I want.

HTMX is HTML with some extensions that make it possible for the server to update a page without reloading it, either in a REST request or over a web-socket. The wire-protocol is HTML partials that replace elements in your DOM.

I started an application in it three weeks ago that I’ll talk about after this series. Tomorrow, I want to talk about why I am going back to VSCode/Copilot after switching to Cursor earlier this year.

Dev Stack 2025: Part III, Django

I learned Django in 2006 and used it as main way to make web applications for side projects until 2021, when I decided to move to node/express for my backend. It’s time to go back.

As I mentioned yesterday, my stack changes are driven by the prevalence of supply chain attacks and my interest in Agentic AI software development. NPM/Node seems especially vulnerable to these attacks, which is why I am leaving that ecosystem. I considered Rails and Django. In the end, even though I think Rails may be doing more things right, I already know Python, use it for other projects, and Django is close enough.

To me, the main reason to pick Rails or Django in 2025 is that it provides good defaults that can be constraints for using AI. When I see vibe coded projects, the AI they use prefers node/express, which lets them do anything, including things that they shouldn’t do. It doesn’t seem to impose or learn any patterns. These constraints also help me not mess things up or notice when the AI is making mistakes.

In my Django app, authentication and an admin panel are built-in. I don’t need to rely on the AI to build it for me. This also means that we (the AI and I) can’t mess it up.

I have also decided to move away from React (which I will really miss), but again, its dependency story is too scary for me. I am going with HTMX and server-based UI (something I have been trying to return back to). I’ll tell you why tomorrow.

Dev Stack 2025: Part II – Linux

I have been developing on a Mac full-time since 2013, but I’m rethinking how I do everything. Switching to Linux was the easiest choice.

To me, software development is becoming too dangerous to do on my main machine. Supply chain attacks and agentic AI are both hacking and data destruction vectors and need to be constrained. Given that, I decided to build a machine that was truly like factory equipment. It would only do development on it and give it very limited access.

I wanted it to be a desktop to maximize the power per dollar, and since I don’t do any iOS development anymore, there was no reason not to pick Linux.

Mac laptops are perfect for my usage as a consumer computer user. The battery life and track pad are unmatched. My MacBook Air is easy to transport and powerful enough. But, as a desktop development machine, Macs are good, but not worth the money for me. I decided to try a Framework instead, which I might be able to upgrade as it ages.

When I got it, I tried an Arch variant first, but it was too alien to me, so I reformatted the drive and installed Ubuntu. I spend almost all of my time in an IDE, browser, and terminals, and Ubuntu is familiar enough.

Having not used a Linux desktop before, here’s what struck me:

  1. Installing applications from a .deb or through the AppCenter is surprisingly more fraught than you’d think. It seems easy to install something malicious through typos or untrusted developers in App Center. Say what you want about the App Store, but apps you install must be signed.
  2. Speaking of App Center: its UI flickers quite a lot. Hard to believe they shipped this.
  3. Generally, even though I have never used Ubuntu Desktop, it was intuitive. The default .bashrc was decent.
  4. I like the way the UI looks, and I’m confident that if I didn’t, I could change it. I need that now that my taste and Apple’s are starting to diverge.
  5. I still use a Mac a lot, so getting used to CTRL (on Ubuntu) vs. CMD (on Mac) is a pain.
  6. I was surprised that I need to have a monitor attached to the desktop in order to Remote Desktop to it (by default).

In any case, I set up Tailscale, so using this new desktop remotely from my Mac is easy when I want to work outside of my office.

My next big change was to go back to Django for web application development (away from node/express). I’ll discuss why tomorrow.

NaBloWriMo 2025

In October, I committed to write a blog every day in November as a kind of NaNoWriMo, but geared to what I usually write. Of course, when November 1 came, I forgot.

Luckily, I am ok with backdating blog posts, so today (November 5), I wrote for November 1-4. I looked through my drafts and picked a few to finish, but it doesn’t look like I have any other drafts good enough to develop.

Here are some things that are going on with me recently (that I plan to write about).

  1. I have gone all-in on Python for web development.
  2. I started a project to implement the ideas in my book, Swimming in Tech Debt.
  3. I am about five months into learning Spanish.
  4. I’m starting on my experiments that will become my 2026 Yearly Theme.
  5. I am almost done with the print version of Swimming in Tech Debt, which should go on sale soon.
  6. I found a mutation tester I like (mutmut) and made a PR to it to add a feature I needed.

February 2025 Blog Roundup

I started using Cursor in February. I went from 0 to a usable commit in less than 20 minutes. Here is my progression:

I continue to be impressed by Cursor and use it for almost all programming now.

I wrote about catalysts at work (inspired by an old post: An Unnamed Programmer in Peopleware is One of my Heroes):

I am working on a book about tech debt called Swimming in Tech Debt. I spent some time thinking about swimming:

I continue to write about code reviews

Fluent Forever Review

I’m learning German for a trip this spring. Last week, I found out about the book, Fluent Forever [affiliate link] by Gabriel Wyner, which I really love. He also has an app with the same name—it’s fine, but very buggy. It’s hard to recommend the app, but I am convinced his process is going to work for me, and the app is better than trying to his process without it. I bought it after trying it out—despite the bugs. If you read the book, and want to do the process, then you should consider the app.

One reason Wyner’s process resonates with me is because it is centered on Spaced Repetition flash cards, which I already use for other things. I use Anki for spaced repetition practice, but his process isn’t easy to implement in Anki.

Wyner recommends building very custom flashcards that don’t use translation. So, I wouldn’t put an English word on one side and the German translation on the other. Instead, he recommends using an image in place of an English word. He wants you to associate the new language with an image so that you map the word directly to a concept, and don’t have to mentally translate through your native language. Since, I am thinking about how to Apply Program Language Learning Techniques to Learn a Foreign Language, and I never translate between programming languages, this makes sense to me.

Each card in his system is personal to you. He doesn’t supply pre-made cards—he wants you to build them. Building them is part of the process. For example, when I made the card “Großmutter,” I spent at least 10 minutes looking at pictures of my grandmother before I found the perfect one. To represent a concept, sometimes I need to combine several images. That time helps cement the concept before I have even tested my memory with the card. Also, I know what I mean by the image—this would be hard to do with someone else’s images.

The Fluent Forever app helps you build cards, implements a spaced-repetition algorithm, speaks the words (to teach pronunciation), and has many other helpful features. Like I said, if you want to learn this way, the app is better than trying to replicate it with Anki or paper (although the book does show you how to do it). It’s also cheaper than the popular language learning apps. The book, though, is worth a read if you want to learn a language.

Swimming to Focus on a Problem

Yesterday, I wrote about how I use Swimming as Meditation. The extreme solitude afforded by the sensory depravation and the rhythmic repetition of strokes, kicks and breaths keep my mind in the present. Usually I try to think about nothing, but sometimes I decide to use the time to solve a problem.

I start the swimming session with a question. I will keep asking myself the question over and over. It’s similar to Natalie Goldberg’s suggestion in Writing Down the Bones to start your writing practice by repeatedly finishing the sentence “I remember…” She is using this as a prompt to keep you writing. I am using a question as a prompt to generate ideas.

One I use often is “What should I blog about today?” The last time I swam, since I am trying to learn German, I asked myself to name German words I know. The questions that work best can be repeatedly asked and answered—meaning, they prompt me to make a list. It’s hard to have a complex string of thoughts that I can remember without being able to write anything down.

Because I can’t write them down, if I have any good ideas, I have to just keep repeating them to myself until I am done swimming. I try to come up with mnemonics that will make sure I remember them. I number them and incorporate them into my stroke counting. That’s usually good enough to keep it top of mind until I can get to my phone.

It seems like it might be hard to swim and think, but actually it’s easier. If I am doing a 30 minute swim, then I will definitely think for 30 minutes. There is literally nothing else to do.

Swimming as Meditation

I don’t have a regular mediation practice, but I’ve started to think of my swimming sessions as one. When I go into the pool with this frame, it gives the meditation more purpose and the exercise extra meaning. I have intrinsic motivation to do each, and it gets combined.

Before swimming, most of my meditation has been guided by an app. I learned how to do it with Headspace, and then moved onto the Apple Watch Breathe app for lighter guidance. But, I do need some prompt to direct my thoughts. Swimming has that built-in because I need to refocus on the parts of my technique constantly.

Whenever I notice that my thoughts have drifted, I count my strokes, kicks, or breaths—or concentrate on their polyrhythmic interplay. I have a cadence of each I am trying to meet, so counting them makes it more likely that I will do it correctly. I also have a target stroke count per lap, so counting is already a part of my swimming. It incidentally keeps me in a meditative zone.

It also helps that the pool is a sensory depravation chamber. I wear non-corrective goggles and earplugs, so my vision and hearing are dulled to start, and being in the water gives me nothing to see or hear anyway. It’s the only workout I do without any distraction, and so I have been avoiding underwater headphones to keep it that way. This may be the only waking part of my day with extreme/literal solitude.

I picked up swimming again because it’s the central metaphor of my book on tech debt. This meditation frame also applies to coding. When I’m in a coding flow, I must stay present to extend it. Like swimming, the interplay of the purpose of my work and enjoyment of meditation makes me want to keep going.