Hey! You can find me on Mastodon and Bluesky!

I recently wanted to get a better overview of our household’s finances. One misconception about my new found independence might be that my previous employments left me so wealthy that I have no reason to ever work again. Unfortunately not! No, independence merely means “I have my own business and regularly get to choose who I work for.” There are plenty of software tools out there to help with getting that financial overview, but for some reason I failed to find one that matches my specific needs (e.g. compatible with Swedish banks, has a good Desktop app, multiple bank accounts with specific filtering of transactions). So I decided to write one. This post is an excuse to reflect on writing small apps.

Over the last year, I have written quite a few small apps for myself, like that finance tool. My personal highlights include a search tool to quickly perform full-text search on large number of text changes in Perforce and a small database tool that scans your hard disk for sound files in the background incrementally so you can search them more easily (for some rudimentary sound design – the crucial point here is that the tool is fully incremental and never, never ever blocks and makes you wait). 15 years ago all my apps used to be C# and WinForms. This doesn’t click with me anymore. All my current apps are Win32 C++ applications with a DX12 renderer and all GUI rendered through DearImGui.

This time, when writing that finance tool, I was for the first time quite surprised by the speed at which I was able to produce something useful: over the course of merely three evenings I was able to implement all features I needed to get the information I was after. How did that happen so quickly? Some thoughts:

First, I experienced minimal discomfort during those programming hours. The most common reasons for discomfort that I experience are 1) having to use something I do not understand but feel I need to and b) using things that are more complicated than I need them to be. I often find the frustration of using someone else’s complex solution way worse than the work required to build a simpler, more restricted, and maybe even less optimal version myself. For example, I recently eliminated CMake from my setup and wrote my own build system, which removed one such case of a complex dependency. I have my own implementation of all the “STL-like” things I need, which eliminates another large class of unpleasantly complicated things to use. My implementation is deliberately simpler (e.g. it does not support destructors or move semantics, and template usage is minimal). In short: I have a library of code that I have written for me specifically. It is my code, it works how I want it to work, and the friction is minimal. (This is incidentally why I am still struggling with web apps: so much unnecessary complexity for my use cases.)

Second, when I do hit friction then I have a process for handling that. The process is “write down what annoys me and then work around it for the moment.” By now it is usually minimal stuff, so my annoyance levels are low enough to just ignore them. My process for writing stuff down is covered in Programming Stamina. For example, I recently came around to the idea that I should probably replace most uses of size_t in my code with int64_t, including in some widely used containers. I’ll do that some time, but not now. Write it down, the day will come, but it is not today. (Editor’s note: the time did indeed come.)

Third, I have a minimal program that I copy around to base my new tools on. The code is essentially the Win32 boilerplate and the “renderer”, if you can call the hastily slopped together lines of DX12 I have that. There is no point in rewriting this, and I have multiple times tried and failed to make it “reusable” but never likd the result, so I just copy it around. That’s still different from using say SDL for this, since I occasionally need to dive into the code and make a spot change for a program, and I do not want to pull in a complex codebase like SDL as a dependency just because I need to create a window.

Fourth, writing tools with DearImGui is fun and minimizes context switching. Oh the irony that I now praise one of my few dependencies: Dependencies can be great when they are maintained by someone that you trust and share values with, I suppose. From my perspective, the biggest win of immediate mode GUIs is that I can do everything in code. I do not need to switch to a visual editor, I do not need to switch to some XML, I do not need to suddenly write some declarative soup to get a UI to show up. (I am very much not fond of declarative languages. Stating what to do specifically and how to do it is a feature the main feature of computers!) Having a well-supported imgui library with a proven track-record and a trusted maintainer is maybe one of the main enablers of this entire flow for me. As an added bonus, immediate mode GUIs pair excepetionally nicely with code hotreloading via Live++.

And finally fifth, I have been ruthless in what I implement and what I do not implement. When you are your own customer you get to choose what is important. I only spend time on high-value things. For example, I did not write any code to import bank statements. I do not need it, because I only need to import the initial data set, and that I can let another more bespoke script convert into a long array of data that I just bake into the executable. When I then have ideas for what to do with the tool and the data, I follow the exact same process as outlined above: write them down and continue with the high value stuff. Might get to the new ideas, might not. Who cares. Future me can implement bank statement import when he actually needs it.

To my big surprise, the one thing that was not relevant for reducing friction was choosing a higher level language. Maybe there is a point to be made about a better ecosystem. I like that C# has a broad and reasonable standard library and mature tooling, for example, but I personally vastly prefer a language that actually makes me touch the bytes myself and does not make me put everything into a class (- I still quite like C#! Just not as much as I used to). I just value being able to see the compiled code more than I do the convenience of not having to think about memory management (…until you inevitably need to but now have your hands tied behind your back). It’s not unlike how C# is just more productive than Python for me, because there is static typing. It turned out to be more fruitful to just implement the standard library and tooling myself instead of living with the constant base level of discomfort from using a tool that maybe just was not made for me.

There is some ambiguity here between “little friction” and “high productivity”. I think I can be highly productive in a variety of languages and setups. But what does it cost me? How much will I hate the software I write? (Let’s ignore the base-level of hatred for software and ironically our tools in particular that all of us programmers seem to have.) The point of minimizing friction is not about maximizing productivity, but about making it sustainable. It’s about how I want to program, and how I can do that efficiently. It’s asking: How do I enjoy programming? How do I write programs in a way that I come back to them after a long day and still move forward? How can programming be effortless for me? And I think I learned a bunch about that now.

I am also happy to announce that I am now sponsoring DearImGui development.