One of the fundamental ideas behind the CPN project's development is "Software Annealing". Annealing, oversimplified, is the heating and cooling of a material to align molecular structure and merge crystaline regions within the material, generally hardening and improving other desirable features. Software annealing is philosophically similar, in higher dimension:
- Establish or update the project's heading or scope.
- Establish applications/use-cases of the project that stretch its current state.
- Refactor or evolve the project into a new "simple" or "solid" state.
- Go to 1.
It sounds simple; and at a high level, it is. The process is very Agile™, which gives it great optionality, and it aligns well with the naturally evolving process of discovering the new, valuable, insightful form for the software. One of the risks of software projects is that software can be whatever you make it, which tragically also means it can be whatever you imagined it maybe should be at 1 AM one fateful night.
This brings up one of the often unsung hero's of successful software: good applications of said software. This can be users, or other apps serving users, etc. These applications of the software-under-optimization are the neurons that propagate gradient from "the market" (the real world), and anchor the software in reality. It's the "personal software" workouts app that motivates flexibility and client-server capabilities, it's the TPC-C benchmark that ensures performance, it's the scraper that motivates complex binding semantics, etc.
The power of these applications is even higher when driven by the project author. By looking at the high level goals of the project, and finding gaps with what is being tested now, the author can pattern match those gaps to applications that would truly test them. By doing continuous narrative building (it's all narrative building), you can measure the delta between opportunities identified and recorded in the past and see how they align in total. These notes on opportunities and frictions from the past are the crystal dislocations waiting to be annealed. This is why I love threads so much as a human and machine-read planning and execution journal. They make execution easy and retros/insight mining almost free.
Oh yeah, LLMs! They make this whole process way faster. LLMs love a verifiable goal and a well described task. They are good foils for thinking through designs and problem framings (especially the latest models), and can then execute on the whole loop with some hand-holding. And maybe one of the easiest to overlook boons they bring is their surprisingly strong inductive capabilities. After enough "data" generated by way of applying the software-under-application, you can sometimes just point a sufficiently smart code agent at a set of threads with a vague "I get a vague sense that our migration story is complex" prompt and it will come back with some surprising insight.
Another practically valuable property of this strategy for solo developers is that it keeps the project interesting. It is very easy to park ideas that you capture, but don't want to act on yet, without it just going off into the ticket abyss. You are essentially maintaining a portfolio of options, of threads to pull when you are inspired or the time is right. I've got a thread on net change data capture (so postgres/etc can tail) on the shelf, while establishing identity capabilities that is more pressing. Very fun.
Appendix
Workouts App
Making software for yourself is great. The workouts app is software I made to track workouts. Probably one of the most common personal projects, and honestly the second one I've made.
This one is pretty cool though, if you don't mind me bragging:
- It implements petri nets for both the front and and backend, with semantics for uncertain network transmission
- It handles idempotence and reconciliation implicitly due to the foundational token movement concepts of CPNs
- That means I don't have to wave my phone around in the gym where the wifi is always bad to be confident my workout gets submitted
I was also inspred by a recent HN comment about tracking strength training progress using "Pareto Fronts": strength training and physical fitness in general is multi-facted and can be hard to be certain if you're really progressing, and adding this to the workouts app should make it easier to suss out.
Beads, Gastown, Buzz, etc
The vibe that I get when I hear about software factories is that they are kinda missing the point. They're focused on "coding isn't the hard part", and betting that the thing to focus on is orchestration. Focusing on orchestration is kind of a bet against increasing LLM capabilities - if we start running Fable on ASICs, do we need things to be orchestrated? Or is a single threaded loop fine? It strikes me that these systems may become useful, but only briefly before "Fable on ASICs" makes them irrelevant (and probably destroys the fabric of capitalism).
Thinking about it through this lens, software annealing seems to be about enumerating and revising the bets of what is valuable over time. For things like the CPN project, its core bet is easy to describe (the arc graph can correctly encode all state transitions), but not quick to turn into complete software ready to replace postgres, temporal, or fastapi. You need to continuously think about what learnings to bake into the framework, about what requirements are ancillary. Claude would just love to add yet another concept to your codebase, and you have to have the taste to say no! No is the other side of the coin from deciding what is valuable.