Compare commits

...
4 Commits
5 changed files with 89 additions and 13 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ Posts live as markdown files in git and compile into the BEAM at build time: zer
The project structure is modular, I wanted to have a personal blog, and an easy way to add an 'engineering' blog to fledgling SaaS products, as well as release notes. The release notes now also serve to announce new features on my blog.
Status: Expirimental. Works on my server ;-).
Status: Experimental. Works on my server ;-).
Enjoy, [Willem van den Ende](https://willemvandenende.com)
@@ -1,7 +1,7 @@
%{
title: "Learning to Swim test",
author: "Willem van den Ende",
tags: ~w(ATDD ComprehensionMaxxing CollaborationMaxxing),
tags: ~w(ATDD ComprehensionMaxxing CollaborationMaxxing SyntheticTDD Refactoring),
description: "The faster you can build, the more pressing communication with others and understanding together becomes. You can build software to promote understanding and collaboration, but where do you start? I found a foothold in the 'swim tests' paper and existing integration tests.",
published: false
}
@@ -36,6 +36,7 @@ I liked:
- backlinks to the tests from the dialogs in the actual application
- display of errors inline
- The swimlanes, and the way events are used
- Standard flows and variations on them, implemented and inspectable simply
I think the paper predates the Event Sourcing hype, seeing the past-tense framed things in the swimlanes
@@ -65,39 +66,72 @@ See below in working in small steps on how I am dealing with that.
From my own failures
----
The swim systems paper appealed to me, because I have trouble keeping an overview of workflows with multiple steps. This was always a challenge working in the XP way, as we very quickly can create a well-tested app with complicated flows. Keeping the whole coherent and 'ready to mind' is hard. "Ready to hand" with good unit tests became very cheap, but seeing the forest was sometimes difficult.
- being able to see the whole and have confidence it fits together coherently
- testing as a feedback mechanism was secondary, strangely enough
Having the screens, step by step, gave me confidence where I was, and made it easy to identify the next step. It did turn out to have value as a technical feedback mechanism earlier than expected. I had worked bottom up for part of a feature, and added the next step in a flow once the parts were done. Some bits to integrate them were missing, as evidenced by the new step. Good encourgement to work acceptance test driven the next time.
On being able to have confidence in coherence
---
The swim systems paper appealed to me, because I have trouble keeping an overview of workflows with multiple steps. This was always a challenge working in the XP way, as we very quickly can create a well-tested app with complicated flows. Keeping the whole coherent and "ready to mind" is hard. "Ready to hand" with good unit tests became very cheap, but seeing the forest and the trees was sometimes difficult.
This became worse with LLM generated systems. When I can create a prototype out of thin air in a couple of hours, with hundreds of tests, and several screens and can let a coding agent produce the demos (see previous posts) it feels great. But when someone else is interested and asks me how it fits together, that becomes a lot harder.
I was hesitant to take some of my visual collaboration tools to market, and I did not understand why. After building the first steps of workflow tests I do understand. It may look like a collaboration tool is about the sticky notes, but the magic is in the collaboration rules that are encoded in things like how groups are structured, how invitations works, what the unit of a 'tenant' is in a SaaS applications, who gets to (dis)invite who, how, when? Or in moderation: who invited this _Person_ and why?
I was hesitant to take some of my visual collaboration tools to market, and I did not understand why. After building the first steps of workflow tests I do understand. It may look like a collaboration tool is about the sticky notes, but the magic is in the collaboration rules that are encoded in things like how groups are structured, how invitations work, what the unit of a 'tenant' is in a SaaS applications, who gets to (dis)invite who, how, when? Or in moderation: who invited this _Person_ and why?
It is great brainstorm-building a mobile first product outcomes focused board, but then adding teams and seeing bits of flow missing is annoying. These flows are neccessary for any collaborative application, visual or not, and the are different, because peoples' roles and assumptions are different for each.
It is great brainstorm-building a mobile first product outcomes focused board, but then adding teams and seeing bits of flow missing is annoying. These flows are necessary for any collaborative application, visual or not, and they are different, because the combination of peoples' roles and assumptions are unique for each application.
So I wanted, just for myself, to see as much of the flow as possible. End-to-End tests through browsers are now very cheap to make (I can make dozens in a day), but maintaining and running them is not. Especially when I am working on my laptop with a coding agent. Having sandboxed the agent, accessing a browser is not trivial.
The unit and integration tests I have so far do give me confidence that most things work, but not that the whole application flows hang together as I want. This was triggered by a stakeholder asking: "Where are we with <tool> 2.0?" . (more about <tool> later).
The unit and integration tests I have so far do give me confidence that most things work, but not that the whole application flows hang together as I want. This was triggered by a stakeholder asking: "Where are we with <tool> 2.0?" . (more about <tool> later. previous blog posts drafts failed on digressions).
Every application has workflows. They may not appear to be core, but they shape collaboration, so they are.
Working in small steps, AI augmented where useful
=====
I had an integration test that could serve as a starting point. But the workflow only had two steps. Several things are taken care of beforehand, analogous to the `login(''developer1')` in the Swim Systems paper. At least it was a good place to start, so the process was roughly:
1. Find out how to write pages and dialogs (a part of the page) as html
2. Decide how to collect these as the test progresses
3. Turn the collected parts into a report
4. Refactor the existing test towards a DSL
5. Add more steps
6. Go to 4.
For 1. I found a forum post, and I already had some [Synthetic](/blog/engineering/2026/07-13-synthetic-tdd.md) tests. This was also a good opportunity to re-read [the documentation](https://phoenix-live-view.hexdocs.pm/Phoenix.LiveViewTest.html). Rendering pages, components, selecting elements and getting the text back is all built in, so all we need to do is wrap it in a page and save the parts. I did consider writing the reports out as markdown, with html snippets at some point. When rendering html to a pdf, the page breaks happen in the middle of screenshots sometimes. But the PDF already lacks the styling.
I initially iterated with [Pi](/blog/engineering/tag/pi.dev) on how to collect tests. I had a fancy idea of collecting the various dialogs in a process (well supported e.g. by Elixir GenServers), then thought of doing it the unix way (write out dialogs, than `cat` them all together), and ended up collecting step outputs in a list, and rendering the list at the end. This did require re-ordering the test a bit: the `assert` has to come at the end, after creating the report.
My assumption was that a model could generate more steps, after refactoring towards a simple flow of steps. The generated tests had some noise in parsing outputs to determine inputs for the next steps. Finding the right extractions was a bit of work, and at the same time gave me a better understanding of what I wanted.
Away from the desk, away from the screen?
----
I was mostly away from my desk last week. After getting three steps working, in small steps, refactoring by hand (my local model had some trouble moving things around in to files, and I needed to learn more about how to organise tests and support code in a Phoenix Liveview project ), the basic flow is now at five steps. Pi with Deepseek v4 flash did most of that, with me doing 'yes' prompts from my phone.
![Screenshot of Pi session - featuring 'insufficient credits'](/static/images/blog/2026/pidev-step5-generated.png)
This insufficient credits message hasn't happened to me in a while. I deposited 25 USD in may last year on OpenRouter. Since then I mostly used Claude Code or local models. Being away from my desk means running Pi on a server, with deepseek. I spent about 10$ in the last month, preparing a keynote and TDD with AI workshops for Philips (hit me up if you are interested too, at QWAN we are responsibly extending our offerings, now that we have a better understanding of how to augment teams, and improve the outcomes and quality using coding agents). So probably about 1 or 2 $ on workshop preparation and 8 for the testing support and bringing a vibe TDD'ed app to production.
It is nice to be able to make progress while having friends over. I have learned to not multi-task too much, and when a question is too big to answer on my phone, I will just percolate on it. Good designs come from working on that - you have to be seen working for creativity to happen, and from stepping away from the screen and coming back with a fresh perspective.
Show me the reports
====
TODO add validation failure report, and full flow so far.
Reworking is easier than writing
====
Reworking and refactoring existing user-focusing integration tests towards this turns out to be easier than writing about it. A number of ideas collide, and I had trouble keeping track of the references. So the first blogpost about this was the "further reading" section.
And here as well, Programming as theory building works.
And here as well, Programming as theory building works. I built towards the principles above, learnt a few things, got some value out early, and now have an idea of the next steps.
Further Reading
@@ -109,3 +143,7 @@ The Swim Systems paper is well worth reading, it is as good as any of my favouri
Felienne on Programming as Theory Building
Refactoring to Patterns
John Nolan on explaining what happened after the fact
Machiel Groeneveld on wanting the reasoning
@@ -0,0 +1,38 @@
%{
title: "Developing with open weights models only, three months in",
author: "Willem van den Ende",
tags: ~w(pi.dev open-weights ),
description: "It is a bit over three months ago that my linkedin post about cancelling my Claude Max subscription went viral. Time for an update. The first six weeks were uneventful, then I started missing some things from before, and yesterday I closed the loop.",
published: true
}
---
I blogged about [My local agentic development setup](/blog/engineering/my-local-agentic-dev-setup-today) the day after my post about cancelling my Claude Max subscription and going all in on local models went viral.
I am still using the same flexible harness - [Pi.dev](/blog/engineering/tag/pi.dev), with surprisingly few extensions (apart from yesterday, see below for prime-agent). I had expected to add web-search, but even my local models have a lot of knowledge, know how to use tools and look up urls from documentation. Enough to start building [Swim the test](/blog/engineering/swim-the-test), which is quite niche, into an existing system. I occasionally paste a hand-searched link into the prompt and that is enough.
The first six weeks were uneventful. I didn't need to create large prototypes in a day like before, that helped. I was busy preparing larger sessions (a coding dojo with 70 participants and 10 facilitators for a UK client, and a keynote about AI and TDD and a workshops on AI with TDD for Philips Image Guided Therapy). So mostly smaller things, and sometimes making small in-the-loop changes to existing code.
Then in a conversation with Chris Matts he mentioned he sketches UI on a piece of paper and then lets one of the hosted solutions (Figma or ChatGPT) create a screen out of it. I wasn't set up to do that. After that I have set up [image recognition in Pi.dev](/blog/engineering/enabling-a-local-model-to-explain-images-in-pidev). Surprisingly good. I haven't used it to generate screens, but could make that with some extensions.
In July I went back to working on a larger piece of software, and improvements to local inference engines were coming in thick and fast. I can now run Qwen3.6 27B, their dense model, at conversational speed, and my previous go to, their 35B mixture of experts model, runs a lot faster as well. For smaller, me-in-the-loop changes with tests, the 35B model works quite well. For trickier things, or larger independent runs, where the coding agent runs through a list of tasks and executes them in sub-agents one by one, the 27B model performs better. Slower per token, faster to outcome.
With [mtplx](https://github.com/youssofal/mtplx) instead of LLamaCPP I can now run the dense Qwen3.6 27B at conversational speed (was below 20 tokens per second, now often 30 at the start of a conversation). This means I can run more complex development tasks locally. If it slows down later, I'll go do something else, as long as it can finish the job independently.
As an example, it managed to find something properly obscure that Deepseek v4 flash also could find, but the 35B model could not. I am keeping that private as a benchmark. Before this, none of the MLX (mac accellerated) inference engines could handle long context (for me). Mtplx does that - speed does not matter if you can't get a good outcome.
MTPLX is also a proper consumer solution. It comes with a GUI to select models and see how it is running. It will figure out the best parameters to run a model with by running a benchmark on your machine after downloading a model, and comes with pre-selected models and quantizations. The screenshot below was after installing a smaller variation of the qwen27B model. Before this I had never seen any of them do more than 20 tokens per second. Around 30 is good enough for a conversation for me.
The screenshot below was taken when I installed a smaller version of the Qwen 27B model. It shows a few sessions tested on my laptop, and which one was found to be fastest, for me.
![Mtplx installation screenshot](/images/blog/2026/mtplx-install.png)
I still have LLamaCPP, but mtplx does well enough at the moment. I would us LLamaCPP when I want to run multiple smaller models on my mac simultaneously - mtplx so far only runs one model at a time. No problem for 35B and 27B as more than one does not really fit in 64GB (V)RaM.
Since the school holidays were starting and I am away from my desk more often, I revived my [remote environment in a virtual machine](/blog/engineering/how-to-get-started-with-the-pi-coding-agent-on-a-vps), so I could develop on my phone. I had used DeepSeek V4 Flash in part when preparing exercises. This model can be locally on slightly more VRAM than I have.I use openrouter for it. This has worked very well for adding features to existing code, doing longer running implementation sessions etc. It is cheaper to host than Qwen 3.6 27B apparently.
On Friday I spent a day with prime-agent. This is a ready-to-use Recursive Language Model adaptation of Pi. This runs instances of Pi on subtasks, and creates memories of things that could have been done better. It appears to do long running tasks without a ticket system like yaks, beads or a markdown file well enough. It is an example of not attaching new ways of working to old flows (ticket systems, version control). There may be better ways to discover. RLM appears to be one of them. I am doing `new session` less often, longer contexts seem to work well enough (although slower). As the memory built up, starting 'fresh' also is fast enough also is fast enough
[Prime-agent](https://github.com/PrimeIntellect-ai/prime-agent) means I can do what I did with claude code before, developing larger prototypes with tests in a conversation. But now with smaller open weights models. The 0731 release of deepseek-v4-flash appears to be strong. Prime-agent with feels more coherent than claude code in april. After three months of not doing larger prototypes, and developing all the things I had thought of before, I now have some new ideas. The harness is at least important as the model, and experiments in harness development are ongoing by many people.
Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 458 KiB