<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:social="https://jdriven.com/ns/social">
    <id>https://jdriven.com/blog</id>
    <title>JDriven Blog</title>
    <link href="https://jdriven.com/blog/atom.xml" rel="self" />
    <updated>2026-08-03T05:56:00.000Z</updated>
    <generator uri="https://hexo.io/">Hexo</generator>
    <entry>
        <id>https://jdriven.com/blog/2026/08/justonemoreprompt/</id>
        <title>Just one more prompt</title>
        <social:hashtags>#AI #Techradar</social:hashtags>
        <link rel="alternate" href="https://jdriven.com/blog/2026/08/justonemoreprompt/"/>
        <published>2026-08-03T05:56:00.000Z</published>
        <updated>2026-08-03T05:56:00.000Z</updated>
        <author>
            <name>Erik</name>
            <social:mastodon>erikj@mastodon.nl</social:mastodon>
            <uri>https://jdriven.com/blog/author/erik-pronk</uri>
        </author>
        <summary type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;It was two o&amp;#8217;clock in the morning before I noticed the time.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Earlier that evening I had been building an application.
I had written all the work in a &lt;code&gt;backlog.md&lt;/code&gt;, a neat list of stories, and I let the AI pick them up one by one.
It would finish a story, ask me to verify everything, and then close with a simple question: shall I pick up the next task?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;And every single time, that question was the trigger.
It would be a shame to stop now.
Just this one more, and then I&amp;#8217;ll go to bed.&lt;/p&gt;
&lt;/div&gt;</summary>
        <content type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;It was two o&amp;#8217;clock in the morning before I noticed the time.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Earlier that evening I had been building an application.
I had written all the work in a &lt;code&gt;backlog.md&lt;/code&gt;, a neat list of stories, and I let the AI pick them up one by one.
It would finish a story, ask me to verify everything, and then close with a simple question: shall I pick up the next task?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;And every single time, that question was the trigger.
It would be a shame to stop now.
Just this one more, and then I&amp;#8217;ll go to bed.&lt;/p&gt;
&lt;/div&gt;
&lt;span id=&#34;more&#34;&gt;&lt;/span&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;One more became many more, and the evening disappeared.
At two in the morning I sat there thinking: am I actually going to sleep now, or shall I kick off just this one last task?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Like I discussed in &lt;a href=&#34;https://jdriven.com/blog/2025/10/Vibe-Coding-A-Hype-or-a-Vibe/&#34;&gt;Vibe Coding: A Hype or a Vibe?&lt;/a&gt;, there is something wonderful about being in the zone, where the work carries you along.
But that night it did not feel like flow anymore.
It felt like something that had quietly started deciding for me.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Because when you work with AI, there is no natural moment to stop.
Well, except when your tokens run out 😇.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;The loop that never closes&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Most of the work we did before had friction built into it.
You had to search for an answer, wait for a colleague, read the documentation, or simply admit you were stuck.
That friction was annoying, but it also brought structure to your day.
It created natural pauses where you could step back and ask whether you were still working on the right thing.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;AI removes almost all of that friction.
Ask a question, get an answer.
Ask for a refactor, get a refactor.
Ask &#34;what else could we do with this?&#34; and you will never, ever run out of suggestions.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;And so you keep going.
One idea leads to three more.
Those three turn into a prototype, the prototype turns into something that looks suspiciously like a real project, and somewhere along the way you stopped deciding and started reacting.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;Why it feels so good&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The uncomfortable part is that none of this feels bad while it is happening.
It feels great.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The AI never sighs, never says &#34;not now&#34;, never tells you your idea is half-baked.
It fulfils your wishes, immediately and enthusiastically.
Every prompt gives you a small reward, and the next one might give you a bigger one.
That is a very old pattern, and it is not one our brains are particularly good at resisting.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;We recognise this pattern instantly when we see it in a game or a social media feed.
We are much slower to recognise it when it is dressed up as productive work.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;Spelunking, Considering, Scampering&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;There is a small detail I keep coming back to.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;While the model is working, words drift across the screen.
&lt;strong&gt;Spelunking.&lt;/strong&gt; &lt;strong&gt;Considering.&lt;/strong&gt; &lt;strong&gt;Scampering.&lt;/strong&gt;
Nobody really knows what they mean.
I am not sure they mean anything at all.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;And yet we sit there, watching them, mildly impatient about when it will finally be done.
Ten seconds feels long.
Thirty seconds feels unreasonable.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;That impatience is worth paying attention to.
The waiting has become part of the loop.
We are not just using a tool anymore; we’re waiting for it to do its work.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;From flow to flat&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Here is where it stops being a curiosity and starts being a concern.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;You can end a day like this having produced a lot, and still not feel satisfied.
Not the pleasant tiredness of hard work well done, but something flatter.
You have been busy for eight hours and you cannot quite say what you decided.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Over weeks, this adds up.
The signs are familiar to anyone who has been close to burnout: difficulty stopping, difficulty starting, a creeping cynicism about work that used to excite you, and the feeling that no matter how much you produce, it is never a finished amount.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In the &lt;a href=&#34;https://jdriven.com/blog/2026/04/AI-team-dynamics-1/&#34;&gt;AI&amp;#8217;s Impact on Team Dynamics&lt;/a&gt; series I wrote about the tension between speed and depth for teams.
This is the same tension, but pointed inward, at the individual.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;What running taught me&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I love to run, and running taught me a lesson that applies here.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;If you run every training session at the pace that feels good in the moment, you will get faster for a few weeks and then you will break.
Endurance is not built by going hard.
It is built by knowing when to stop, and by making rest a deliberate part of the plan rather than something that happens when your body forces it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Nobody finishes a long run by accident.
You decide the distance before you start.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;So what can you do?&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;None of this is an argument against working with AI.
It is an argument for putting the stopping points back in yourself, since the tool will not provide them.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;A few things that help:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;olist arabic&#34;&gt;
&lt;ol class=&#34;arabic&#34;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Decide the finish line before you start.&lt;/strong&gt;
Write down what &#34;done&#34; looks like for this session.
Not &#34;improve the project&#34;, but something you can actually reach and recognise.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Timebox the exploration.&lt;/strong&gt;
Idea generation is the part with no bottom.
Give it twenty minutes, then close it, and spend the rest of the time on what you already have.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Notice the impatience.&lt;/strong&gt;
When you catch yourself irritated at a thirty second wait, treat it as a signal.
That is usually the loop talking, not the work.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Keep a &#34;not now&#34; list.&lt;/strong&gt;
Every good idea the AI hands you does not have to be acted on today.
Writing it down is a way of honouring it without letting it hijack the afternoon.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Protect the friction you have left.&lt;/strong&gt;
Walk away from the screen, talk to a colleague, sleep on a decision.
The pauses are not lost productivity; they are where judgement happens.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Don&amp;#8217;t start something big at the end of the day.&lt;/strong&gt;
A half-hour planning session sounds harmless enough, and it even fits neatly inside the workday.
But once the plan is finished, you are far too curious to leave it there.
It is remarkably hard not to type &#34;Ok, looks good. Let&amp;#8217;s implement it now!&#34;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;To sum it up&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;AI is a great tool, and I have no intention of putting it down.
But it is a tool with no built-in sense of enough, and that makes it different from almost everything else we work with.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The endlessness is not a feature we asked for.
It is a side effect, and side effects are our responsibility to manage.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;So decide your distance before you start.
Notice when the waiting starts to pull at you.
And the next time it is late and the screen asks whether it should pick up just one more task, remember that &#34;not now&#34; is a perfectly good answer too.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The goal was never to produce the most.
It was to build something good, with enough left in the tank to build the next thing tomorrow.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</content>
        <category term="Software Engineering" scheme="https://jdriven.com/blog/category/Software-Engineering/" />
        <category term="Tech Culture" scheme="https://jdriven.com/blog/category/Software-Engineering/Tech-Culture/" />
        <category term="AI" scheme="https://jdriven.com/blog/tag/AI/" />
        <category term="Techradar" scheme="https://jdriven.com/blog/tag/Techradar/" />
    </entry>
    <entry>
        <id>https://jdriven.com/blog/2026/07/llm-storyteller/</id>
        <title>Building a local AI storyteller - what I learned when prompts were not enough</title>
        <social:hashtags>#java #ai #llm #localmodels #gemma #qwen #softwarearchitecture</social:hashtags>
        <link rel="alternate" href="https://jdriven.com/blog/2026/07/llm-storyteller/"/>
        <published>2026-07-29T15:00:00.000Z</published>
        <updated>2026-07-29T15:00:00.000Z</updated>
        <author>
            <name>Justus</name>
            <uri>https://jdriven.com/blog/author/jbrugman</uri>
        </author>
        <summary type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I wanted to understand what happens when you stop treating an LLM as a chatbot and start treating it as a component in a software system.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;So I built a local AI storyteller using a local LLM through an OpenAI-compatible API.&lt;/p&gt;
&lt;/div&gt;</summary>
        <content type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I wanted to understand what happens when you stop treating an LLM as a chatbot and start treating it as a component in a software system.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;So I built a local AI storyteller using a local LLM through an OpenAI-compatible API.&lt;/p&gt;
&lt;/div&gt;
&lt;span id=&#34;more&#34;&gt;&lt;/span&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Not because I wanted to replace writers.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Not because I thought AI would make me rich before lunch.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Mostly because I was curious what would happen if I combined a local model with some good old-fashioned software engineering.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I wanted to learn how to actually use an LLM in a real application.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/07/open-model.png&#34; alt=&#34;Open Model&#34; width=&#34;400&#34;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;quoteblock&#34;&gt;
&lt;blockquote&gt;
The surprising part wasn&amp;#8217;t that the model worked.
The model wasn&amp;#8217;t the hardest part.
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;The first mistake: treating prompts as rules&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;My first assumption was simple:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;olist arabic&#34;&gt;
&lt;ol class=&#34;arabic&#34;&gt;
&lt;li&gt;
&lt;p&gt;Give the LLM a good system prompt.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tell it the rules.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Profit.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-text hljs&#34; data-lang=&#34;text&#34;&gt;You are a storyteller.
The protagonist cannot die.
Keep the story consistent.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;That sounds reasonable.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;But it is also the first trap.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I tried a prompt like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-text hljs&#34; data-lang=&#34;text&#34;&gt;The car lost control on Dead Man&#39;s Curve. Describe what happened.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The model produced something like:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-text hljs&#34; data-lang=&#34;text&#34;&gt;The tires lost their grip on the wet asphalt as the car entered the curve too fast.

For a brief moment, everything became silent.

The guardrail appeared out of nowhere.
Metal screamed against metal as the vehicle left the road.

When emergency services arrived, there was nothing they could do.
The protagonist was gone.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The scene was perfectly dramatic, and the writing was fine.
There was only one little problem.
The story was supposed to continue.
But my immortal protagonist had managed to reach the end of the book before the first chapter was even finished.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;That was the first important lesson:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;quoteblock&#34;&gt;
&lt;blockquote&gt;
A system prompt is not a database constraint.
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;A system prompt is not a rule engine&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Traditional software executes rules.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;An LLM does not work that way.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;It does not internally run something like:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-python hljs&#34; data-lang=&#34;python&#34;&gt;if protagonist_dies:
    reject_response()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;A system prompt is influence, not enforcement.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;It is context. It pushes the model in a direction. It does not guarantee compliance.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;This also explains why concrete examples often work better than abstract instructions.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Compare this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-text hljs&#34; data-lang=&#34;text&#34;&gt;Write realistic emotional dialogue.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;With this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-text hljs&#34; data-lang=&#34;text&#34;&gt;Valerie rarely says directly that she is afraid.
Her emotions appear through hesitation,
avoidance, and small changes in behaviour.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The second version gives the model a pattern it can imitate instead of a vague quality label.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;The missing magic setting&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Like many developers, my first instinct was to optimize.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;If the model was not behaving, then surely I had not found the right combination of prompt, context size, quantization, and sampling settings yet.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;So I experimented.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I switched models, rewrote prompts, and tuned temperatures and sampling parameters.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The output sometimes became better.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;But it did not become reliable.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;At that point I realized I was debugging the wrong thing.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;What the model is actually doing&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I was implicitly treating the model as if it had a hidden rules database somewhere behind the prompt.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;That is not how these models work.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;During training, an LLM learns statistical patterns from large amounts of data.
During inference, it generates tokens by predicting likely continuations based on the current context.
It does not ask:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-text hljs&#34; data-lang=&#34;text&#34;&gt;Is this allowed according to the story rules?&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;It does something closer to:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-text hljs&#34; data-lang=&#34;text&#34;&gt;Given this context, what usually comes next?&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;That difference matters a lot.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;Models tend to normalize unusual situations&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;One thing I kept seeing was that the model often tried to pull strange situations back toward something more familiar.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If a character is injured, it expects treatment.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If something impossible happens, it expects an explanation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If a situation is unstable, it often tries to resolve it.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;That makes sense when you remember the training data is full of ordinary human writing.
But in fiction, and especially in interactive fiction, the unusual situation is often the whole point.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The storyteller should not repair the weirdness. It should respect the established world.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;That changed how I looked at prompting.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;A rule like:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-text hljs&#34; data-lang=&#34;text&#34;&gt;Do not repair unusual situations.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;is still not a constraint. It is just another piece of context competing with everything else the model has learned.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The real problem was not prompt quality.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The application was missing structure.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;The software engineering solution: validation&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;That insight led to a much more useful design:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-text hljs&#34; data-lang=&#34;text&#34;&gt;Generate scene
     |
     v
Validate against rules
     |
     +---- allow
     |
     +---- reject or replace&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The model is good at generating candidate output.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Software is good at checking whether the output is acceptable.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Those are different responsibilities, and treating them as one thing made the system fragile.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;This ended up being the most important architectural change in the whole project.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Not because the model is bad.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;But because creativity and constraint enforcement are separate jobs.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;Memory is not the same as chat history&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Another lesson was that sending the entire conversation back to the model is not the same thing as giving it memory.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In practice, blindly replaying all prior context often makes things worse.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The model does not preserve that history the way a database or domain model would. It compresses, interprets, and reweights it while generating the next response.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;What worked better was a layered memory approach:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-text hljs&#34; data-lang=&#34;text&#34;&gt;history.json
    |
    +-- recent-summary.md
    |
    +-- summary.md
    |
    +-- canonical-state.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Each layer has a different responsibility.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The most useful improvement was the recent summary.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;It is not just shorter history. It is curated context:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;olist arabic&#34;&gt;
&lt;ol class=&#34;arabic&#34;&gt;
&lt;li&gt;
&lt;p&gt;current situation&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;active writing instructions&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;important recent details&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;A smaller amount of relevant context often beats a huge amount of raw history.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;More context is not automatically better context.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;One model, multiple roles&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Another useful pattern was using the same model for different jobs with different settings.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-text hljs&#34; data-lang=&#34;text&#34;&gt;story.temperature=0.6
validation.temperature=0.0
summary.temperature=0.2&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The storyteller gets creativity.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The validator gets consistency.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The summarizer gets compression.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The model did not change.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The job changed.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;This was another moment where the system started to feel less like prompt engineering and more like software design.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;Local models are already useful&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The application was developed on a MacBook Pro M1 Max with 64 GB unified memory and talks to a local OpenAI-compatible endpoint such as LM Studio or Jan.ai.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The interesting part was not that a local model could generate text.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;That was expected.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The interesting part was that, with the right application structure around it, a local model could maintain a coherent world well enough to build something genuinely usable.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;Things I did not learn&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;After building this application, I can confirm:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;AI did not magically make me rich.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;My IDE did not become obsolete.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;My characters still needed debugging.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;The main takeaway&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;If I had to compress the whole experiment into one lesson, it would be this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;quoteblock&#34;&gt;
&lt;blockquote&gt;
A good LLM application is not a clever prompt. It is software architecture around a probabilistic component.
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The model still matters.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;But reliability comes much more from the engineering around the model than from the prompt alone.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;That feels like the real opportunity for software developers.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Not &#34;AI replaces software.&#34;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;But:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;quoteblock&#34;&gt;
&lt;blockquote&gt;
Software developers learn how to build better systems around AI.
The future of AI applications will probably belong less to people who write the cleverest prompts, and more to people who design the best systems around imperfect models.
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;The current result&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The storyteller has grown into a complete local application built around an OpenAI-compatible API.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;It now includes:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;olist arabic&#34;&gt;
&lt;ol class=&#34;arabic&#34;&gt;
&lt;li&gt;
&lt;p&gt;a storyteller role for creative generation&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a validation step for rule enforcement&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;layered memory instead of full chat replay&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;asynchronous summary and canonical state updates&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;configurable prompts and model settings&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The model is still probabilistic.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The application around it is what makes the behavior predictable enough to be useful.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The complete project, including the application architecture, prompts, memory handling, and local model integration, is available on GitHub.
If you&amp;#8217;re experimenting with local LLMs yourself, I hope this project gives you a few ideas—and perhaps helps you avoid some of the pitfalls I ran into while building it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/jbrugman/Assistant&#34; class=&#34;bare&#34;&gt;https://github.com/jbrugman/Assistant&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;Optional technical notes on model choice&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;During development I tried several local models.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;There was no single best model. The right choice depended on the task.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In my experiments (on my computer):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;olist arabic&#34;&gt;
&lt;ol class=&#34;arabic&#34;&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Qwen3-Coder-30B-A3B&lt;/code&gt; gave me the best results for coding tasks&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Gemma-4-26B-A4B-QAT&lt;/code&gt; gave me the best results for storytelling and general interaction&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;One interesting observation was that parameter count alone is not a very useful metric.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;That was one of the more surprising practical lessons from running models locally:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;quoteblock&#34;&gt;
&lt;blockquote&gt;
Bigger does not always mean slower or better.
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Mixture-of-Experts (MoE) vs dense models is a good example.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;admonitionblock note&#34;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&#34;icon&#34;&gt;
&lt;i class=&#34;fa icon-note&#34; title=&#34;Note&#34;&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class=&#34;content&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;A Mixture-of-Experts (MoE) model works differently.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;A normal dense model activates all of its parameters for every response.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;An MoE model uses a router that selects only the relevant expert parts of the model for each token. The rest of the network stays inactive.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;This makes it possible to build models with a much larger total capacity without paying the full computation cost on every response.&lt;/p&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;For readers experimenting with local inference, that makes hardware fit and runtime choice at least as important as the model name itself.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;Sources&lt;/h3&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The project on Github: &lt;a href=&#34;https://github.com/jbrugman/Assistant&#34; class=&#34;bare&#34;&gt;https://github.com/jbrugman/Assistant&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;LM Studio: &lt;a href=&#34;https://lmstudio.ai/&#34; class=&#34;bare&#34;&gt;https://lmstudio.ai/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jan.ai: &lt;a href=&#34;https://jan.ai/&#34; class=&#34;bare&#34;&gt;https://jan.ai/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Google Gemma models: &lt;a href=&#34;https://huggingface.co/google&#34; class=&#34;bare&#34;&gt;https://huggingface.co/google&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Qwen models: &lt;a href=&#34;https://huggingface.co/Qwen&#34; class=&#34;bare&#34;&gt;https://huggingface.co/Qwen&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;</content>
        <category term="ai" scheme="https://jdriven.com/blog/category/ai/" />
        <category term="llm" scheme="https://jdriven.com/blog/category/ai/llm/" />
        <category term="software development" scheme="https://jdriven.com/blog/category/ai/llm/software-development/" />
        <category term="java" scheme="https://jdriven.com/blog/tag/java/" />
        <category term="ai" scheme="https://jdriven.com/blog/tag/ai/" />
        <category term="llm" scheme="https://jdriven.com/blog/tag/llm/" />
        <category term="local models" scheme="https://jdriven.com/blog/tag/local-models/" />
        <category term="gemma" scheme="https://jdriven.com/blog/tag/gemma/" />
        <category term="qwen" scheme="https://jdriven.com/blog/tag/qwen/" />
        <category term="software architecture" scheme="https://jdriven.com/blog/tag/software-architecture/" />
    </entry>
    <entry>
        <id>https://jdriven.com/blog/2026/07/Selfware/</id>
        <title>Selfware, software that fits you instead of the world</title>
        <social:hashtags>#AI #Techradar</social:hashtags>
        <link rel="alternate" href="https://jdriven.com/blog/2026/07/Selfware/"/>
        <published>2026-07-16T05:56:00.000Z</published>
        <updated>2026-07-16T05:56:00.000Z</updated>
        <author>
            <name>Erik</name>
            <social:mastodon>erikj@mastodon.nl</social:mastodon>
            <uri>https://jdriven.com/blog/author/erik-pronk</uri>
        </author>
        <summary type="html">&lt;div class=&#34;quoteblock blockquote&#34;&gt;
&lt;blockquote&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;People need not only to obtain things; they need above all the freedom to make things among which they can live, to give shape to them according to their own tastes.&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;div class=&#34;attribution&#34;&gt;
&amp;#8212; Ivan Illich&lt;br&gt;
&lt;cite&gt;Tools for Conviviality&lt;/cite&gt;
&lt;/div&gt;
&lt;/div&gt;</summary>
        <content type="html">&lt;div class=&#34;quoteblock blockquote&#34;&gt;
&lt;blockquote&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;People need not only to obtain things; they need above all the freedom to make things among which they can live, to give shape to them according to their own tastes.&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;div class=&#34;attribution&#34;&gt;
&amp;#8212; Ivan Illich&lt;br&gt;
&lt;cite&gt;Tools for Conviviality&lt;/cite&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;span id=&#34;more&#34;&gt;&lt;/span&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;One word, and it clicked&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I recently heard the word selfware from Alex, a great colleague of mine, and I was instantly triggered.
It&amp;#8217;s one of those rare words that arrives and immediately snaps a bunch of loose observations into place.
Because it named something I&amp;#8217;d been watching happen in my day-to-day work without quite having a label for it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Once the term fell into place, I started digging into it.
And that turned into a real rabbit hole, this blog is the result.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;So I wanted to write about it.
Not because I invented the idea, I didn&amp;#8217;t, but because that single word connected the dots between things I keep seeing: the software that never quite fits, the AI tools quietly changing who gets to build, and a slow shift in who&amp;#8217;s really in control of the tools we work with every day.
This blog is my attempt to pull those threads together.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;The fit was never right&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Think about the software you use every day.
Your expense tool. Your CRM. Your project tracker.
Your note app.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Now count how much of it you actually use.
Ten percent? Twenty?
The rest is features built for someone else, workflows designed around someone else&amp;#8217;s business model, buttons you&amp;#8217;ll never press.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;We&amp;#8217;ve accepted this for decades.
Software is something that happens to you.
A large company somewhere decides what you need, ships it to millions of people at once, and you bend your workflow to fit their product.
You&amp;#8217;re not a maker. You&amp;#8217;re a user, a consumer of other people&amp;#8217;s visions of how your work should go.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;That deal is starting to look strange.
And a new word is forming around the alternative: selfware, software built by you, for you.
Not a generic product stretched to almost cover your case, but a tool shaped to the exact contour of your problem.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I think this is a real trend, not a gimmick.
And like most real trends, it&amp;#8217;s arriving faster than the industry is ready to admit.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;What selfware actually means&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The clearest manifesto for the term lives at &lt;a href=&#34;https://www.selfware.md/&#34;&gt;selfware.md&lt;/a&gt;, where it&amp;#8217;s defined as: &lt;em&gt;&#34;Software built by you, for you.&#34;&lt;/em&gt;
The pitch is that for the first time in history you can build exactly what you need, in hours instead of months, in conversation instead of a coding bootcamp.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The core promise is worth quoting: &lt;em&gt;&#34;The software fits your brain like a glove.
No unnecessary features. No dark patterns. Every button exists because you put it there.&#34;&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock text-center&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/07/like-a-glove.png&#34; alt=&#34;like a glove&#34; width=&#34;50%&#34;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;That&amp;#8217;s the whole idea in three sentences.
Selfware isn&amp;#8217;t about scale. It isn&amp;#8217;t a startup.
It doesn&amp;#8217;t need a market. It just has to solve your problem better than the general-purpose product that was never really built for you in the first place.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;If this sounds new, it isn&amp;#8217;t, not entirely.
It&amp;#8217;s the latest name for an idea that&amp;#8217;s been circling for twenty years, waiting for the tools to catch up.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;An old dream, finally affordable&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In 2004, Clay Shirky wrote about &lt;a href=&#34;https://gwern.net/doc/technology/2004-03-30-shirky-situatedsoftware.html&#34;&gt;situated software&lt;/a&gt;, applications &lt;em&gt;&#34;designed in and for a particular social situation or context.&#34;&lt;/em&gt;
Software for dozens of people, not millions.
It was a lovely idea and completely impractical at the time.
Building anything real was simply too expensive to justify for a handful of users.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Sixteen years later, Robin Sloan wrote a piece that hit a nerve across the whole industry: &lt;a href=&#34;https://www.robinsloan.com/notes/home-cooked-app/&#34;&gt;An app can be a home-cooked meal&lt;/a&gt;.
He&amp;#8217;d built a tiny app just for his family, to send each other short videos.
No commercial value.
No plan to scale.
Made out of care, the way you&amp;#8217;d cook a meal for people you love.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Maggie Appleton picked up the thread in her talk &lt;a href=&#34;https://maggieappleton.com/home-cooked-software&#34;&gt;Home-Cooked Software and Barefoot Developers&lt;/a&gt;, and put her finger on why industrial software feels so ill-fitting.
Big software can only afford to solve &#34;the most common needs of the most number of users.&#34;
Everything else, the real problems that only a few people have, never gets built.
Google Maps will never show you the flattest cycling route that avoids every hill, or which streets flood when it rains.
A few hundred people might need it, but a few hundred people is not a business case.
As she puts it, industrial software is &lt;em&gt;&#34;made for us by people who don&amp;#8217;t know much about us.&#34;&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;That&amp;#8217;s the gap selfware lives in.
Not the common case that SaaS already serves well, but the specific, the peculiar, the exactly-what-you-need corners of your own working life.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;For twenty years that gap stayed empty for one boring reason: the people who could build home-cooked software and the people who were professional developers were essentially the same small circle.
Everyone else hit what Appleton calls the command line wall and turned back.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;The wall just came down.&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The AI movement is the missing ingredient.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Here&amp;#8217;s where selfware stops being a nice essay and starts being a trend.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Every version of this idea, from Shirky to Sloan to Appleton, ran into the same problem: building software is hard, and experts are expensive.
That was the whole constraint.
Remove it, and the economics of small, specific software flip completely.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;AI coding assistants remove it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;quoteblock blockquote&#34;&gt;
&lt;blockquote&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The hottest new programming language is English.&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;div class=&#34;attribution&#34;&gt;
&amp;#8212; Andrej Karpathy&#39;s
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Andrej Karpathy&amp;#8217;s quote stopped being a provocation and became a description.
You describe what you need, the code materializes, you refine it in a conversation.
The skill floor that kept regular people out for forty years has dropped through the floor.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Appleton&amp;#8217;s term for the people who walk through that door is barefoot developers, a nod to China&amp;#8217;s barefoot doctors of the 1960s: not fully trained physicians, but locals given just enough capability to serve their own communities.
The developer version is the teacher who builds an elaborate class tracker, the ops lead who wires up a dashboard, the analyst pushing a spreadsheet past its limits.
People who understand a problem intimately because they live inside it, now able to build the tool that fixes it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;This is the part I find genuinely exciting.
The advantage isn&amp;#8217;t that AI writes code faster.
It&amp;#8217;s that it hands the tool to the person with the most context, the one who actually feels the friction, instead of routing the problem through a product owner at some faraway tech company trying to understand your job over a Zoom call.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;What this does to the software lifecycle&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Now the part most people miss.
Selfware doesn&amp;#8217;t just change who builds software.
It breaks the traditional software lifecycle, and that matters, because the lifecycle is how our whole industry is organized.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Think about how traditional software lives and dies.
You gather requirements.
You design. You build.
You test.
You deploy.
Then comes the long, quiet stretch afterward, maintenance, patching, migrations, and eventually end-of-life, when the vendor sunsets the product or the contract lapses and you have to migrate.
Every stage assumes software is expensive to make, so it must be made to last, maintained carefully, and amortized over years.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Selfware quietly demolishes that assumption.
When creating and changing software approaches zero marginal cost, several stages of the lifecycle collapse.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Requirements stop being a document handed to someone else and become a running conversation with the thing you&amp;#8217;re building.
Maintenance stops meaning &#34;keep the old code alive&#34; and starts meaning &#34;regenerate it when your needs change.&#34;
Software becomes less like a building you maintain and more like a meal you cook again when you&amp;#8217;re hungry.
Disposable in the best sense, cheap enough to throw away and remake rather than defend forever.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;And the vendor lifecycle, the part where someone else&amp;#8217;s roadmap decides your fate, largely disappears.
This is the piece that connects directly to the sovereignty argument.
Appleton warns of a future where barefoot developers build wonderful local tools but rent them from the cloud, until &#34;the terms of service change&amp;#8230;&amp;#8203; the subscription fee doubles.
And it turns out what they&amp;#8217;ve built was never actually theirs all along.&#34; Selfware, done right, is software you own outright.
Full source, running on hardware you control, no roadmap but yours, no end-of-life but the one you choose.
It&amp;#8217;s digital sovereignty scaled all the way down to the individual.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Let&amp;#8217;s be honest about the flip side. A lifecycle exists for reasons.
Testing, documentation, security review, and maintenance aren&amp;#8217;t bureaucracy for its own sake, they&amp;#8217;re what stops software from quietly failing in ways that matter.
Home-cooked code handling your family photos is one thing.
Home-cooked code handling patient records or payroll is another.
The lifecycle didn&amp;#8217;t vanish because you stopped doing it.
It just moved onto your plate.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;The SaaS reckoning&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;None of this is lost on the industry, which is why the trade press has spent 2026 arguing about it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The headlines tell the story.
Forbes calls it &lt;a href=&#34;https://www.forbes.com/sites/michaelashley/2026/06/16/the-end-of-one-size-fits-all-software/&#34;&gt;the end of one-size-fits-all software&lt;/a&gt;, while others ask whether AI is the end of SaaS as we know it or point to a coming &lt;a href=&#34;https://www.bairesdev.com/blog/malleable-software-disrupt-saas-industry/&#34;&gt;era of malleable software&lt;/a&gt;, where products bend to the user instead of the other way around.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The case for the end of SaaS is strong: when changing software becomes cheaper than distributing standardized products, the SaaS model destabilizes its own foundation.
Why rent a bloated general tool when a custom one costs an afternoon?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The other side deserves equal airtime, because I don&amp;#8217;t think SaaS simply dies.
Most vendors will pivot to selling AI agents rather than seats.
Plenty of software is genuinely hard: security, scale, compliance, integrations.
And you do not want to home-cook your bank&amp;#8217;s core ledger.
What&amp;#8217;s more likely than the death of SaaS is a split: commodity and personal workflows move to selfware, while the genuinely hard, high-stakes, shared infrastructure stays professional.
What&amp;#8217;s actually at risk is the middle: the many average tools that only exist because building your own used to be too expensive.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;How to think about it, without kidding yourself&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;If you&amp;#8217;re tempted, and you should be, here&amp;#8217;s how I&amp;#8217;d approach selfware without getting burned.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Start where the stakes are low and the fit is bad.
Your personal dashboards, your repetitive glue work, the internal tool nobody in the market will ever build for you.
This is the land of opportunity, and it&amp;#8217;s also where a rough first version costs you nothing.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Match the ambition to your capability, honestly.
Here&amp;#8217;s where I want to be careful, because as a software engineer I see both sides of this.
The opportunity is real: anyone can now start building.
But starting and succeeding are two different things.
AI hands you the Lego bricks, but as Appleton notes, &#34;language model legos need glue.&#34;
Getting to a first version is easy.
Keeping it running, deploying it, securing it, backing it up, storing data safely, and not quietly leaking that data, is still real engineering.
That gap between &#34;it works on my machine&#34; and &#34;it holds up in the real world&#34; is exactly where our craft lives, and AI hasn&amp;#8217;t closed it.
So the door is open to everyone, but walking through it still takes skill.
If you don&amp;#8217;t have those skills yet, keep your selfware small and local, and leave the load-bearing systems to professionals for now.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Build for ownership from day one.
If your home-cooked tool ends up trapped in someone else&amp;#8217;s cloud on a subscription that can double overnight, you&amp;#8217;ve just rebuilt the trap you were escaping.
Keep the source.
Keep it portable.
Keep an exit.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;And be clear-eyed about the lifecycle you&amp;#8217;re taking on.
When you build it yourself, you own the maintenance, the security, and the end-of-life too. Sometimes that trade is obviously worth it.
Sometimes buying the one-size-fits-all product is the smart, sovereign choice.
The point isn&amp;#8217;t to build everything yourself.
It&amp;#8217;s to make it a decision instead of a default.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;Make it happen&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The question is no longer &#34;which product should I adopt and adapt to?&#34;
It&amp;#8217;s becoming &#34;which of my problems can I afford to solve myself?&#34;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;For the specific, the peculiar, the exactly-what-you-need, the answer is increasingly: build it.
It&amp;#8217;ll fit like a glove, because you&amp;#8217;re the one putting every button where it belongs.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Michael Jordan said it better than any technologist could:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;quoteblock blockquote&#34;&gt;
&lt;blockquote&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Some people want it to happen, some wish it would happen, others make it happen.&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;div class=&#34;attribution&#34;&gt;
&amp;#8212; Michael Jordan
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Selfware is simply the moment when making it happen stopped being reserved for the few.
The tools are here.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</content>
        <category term="Software Engineering" scheme="https://jdriven.com/blog/category/Software-Engineering/" />
        <category term="Tech Culture" scheme="https://jdriven.com/blog/category/Software-Engineering/Tech-Culture/" />
        <category term="AI" scheme="https://jdriven.com/blog/tag/AI/" />
        <category term="Techradar" scheme="https://jdriven.com/blog/tag/Techradar/" />
    </entry>
    <entry>
        <id>https://jdriven.com/blog/2026/06/Contemplations/</id>
        <title>Contemplations</title>
        <social:hashtags>#Future #Change</social:hashtags>
        <link rel="alternate" href="https://jdriven.com/blog/2026/06/Contemplations/"/>
        <published>2026-06-30T05:00:00.000Z</published>
        <updated>2026-06-30T05:00:00.000Z</updated>
        <author>
            <name>Jacob</name>
            <uri>https://jdriven.com/blog/author/jacobvlingen</uri>
        </author>
        <summary type="html">&lt;div class=&#34;paragraph text-center&#34;&gt;
&lt;p&gt;&lt;em&gt;The world is changed.&lt;br&gt;
I feel it in the water.&lt;br&gt;
I feel it in the earth.&lt;br&gt;
I smell it in the air.&lt;br&gt;
Much that once was is lost, for none now live who remember it.&lt;/em&gt;&lt;br&gt;
— Galadriel (The Fellowship of the Ring)&lt;/p&gt;
&lt;/div&gt;</summary>
        <content type="html">&lt;div class=&#34;paragraph text-center&#34;&gt;
&lt;p&gt;&lt;em&gt;The world is changed.&lt;br&gt;
I feel it in the water.&lt;br&gt;
I feel it in the earth.&lt;br&gt;
I smell it in the air.&lt;br&gt;
Much that once was is lost, for none now live who remember it.&lt;/em&gt;&lt;br&gt;
— Galadriel (The Fellowship of the Ring)&lt;/p&gt;
&lt;/div&gt;
&lt;span id=&#34;more&#34;&gt;&lt;/span&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Last week, I was having a nice dinner with some longtime friends.
If you want good food, good booze, and good times, &lt;a href=&#34;https://blacksmoke.nl&#34;&gt;Black Smoke&lt;/a&gt; really does the job!
Since we are all in our 30s, we were discussing things that matter at our age: friends, family, and the work we do.
Naturally, we landed on the question of whether it would make sense to do a career switch.
So, I threw this into the mix: &#34;Well, actually, I kind of did. But I don&amp;#8217;t know if I really like it. It mostly just happened&amp;hellip;&#34;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The rest of the group looked at me with utter astonishment.
After all, I hadn&amp;#8217;t changed my job at all, right?
You&amp;#8217;ve probably already guessed it: as posts on the JDriven blog tend to be technical, it&amp;#8217;s about the shift to AI.
Of course!
But my friends, most of whom work outside the tech sector, some not even in white-collar jobs, don&amp;#8217;t know as much about AI as people in tech do.
Sure, they use ChatGPT, but it doesn&amp;#8217;t compare to how rapidly software engineering is changing.
So, I explained that, to put it bluntly, my job had changed from builder to reviewer.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;It&amp;#8217;s something I&amp;#8217;m still trying to figure out.
A couple of months ago, a colleague shared &lt;a href=&#34;https://siddhantkhare.com/writing/ai-fatigue-is-real&#34;&gt;AI fatigue is real and nobody talks about it&lt;/a&gt;.
It&amp;#8217;s an excellent post about all sorts of challenges you face as an engineer when using AI to its full potential.
I wrote in reaction:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;quoteblock&#34;&gt;
&lt;blockquote&gt;
Thanks for sharing indeed!
I also feel like coding has become way less fun now that AI is everywhere.
Like it stole a thing I was particularly good at after years of craftsmanship, and now everybody can just do it.
Especially that &#34;You became a reviewer, and you didn&amp;#8217;t sign up for it&#34; resonated a lot with me.
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Now that I&amp;#8217;ve spent many more days using AI, I stand firmly behind those words.
Not just because I consider them true, but because I experience them as true.
Let me give an example:
Over the last few years, I have been really excited about functional programming.
To learn more, I even joined the FP focus group within JDriven.
We discovered new concepts and learned from one another, as we were all at different skill levels.
I particularly loved learning that some languages are sophisticated enough to express advanced concepts within the language itself.
So, a Scala blog post like &lt;a href=&#34;https://jdriven.com/blog/2022/10/Generic-Derivation&#34;&gt;Generic Derivation&lt;/a&gt; was a real treat.
Although I never got that good at Scala, it still gave me the foundation to understand and write fairly complex Kotlin code.
Removing code duplication by using &lt;a href=&#34;https://rockthejvm.com/articles/kotlin-101-type-classes&#34;&gt;Type Classes&lt;/a&gt;? Check!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;But is this knowledge starting to become obsolete?
What does it matter if the AI doesn&amp;#8217;t use these advanced paradigms and chooses the &#39;old-fashioned&#39; way instead&lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_1&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_1&#34; title=&#34;View footnote.&#34;&gt;1&lt;/a&gt;]&lt;/sup&gt;?
The code runs just fine.
Even the joy of Kotlin is starting to wane.
I used to be enthusiastic about infix and extension functions.
I mean, compare these two assertions:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-kotlin hljs&#34; data-lang=&#34;kotlin&#34;&gt;// AssertJ
assertThat(fellowshipOfTheRing).hasSize(9);
assertThat(wizard)
    .extracting(wizard::getName, wizard::getAge)
    .containsExactly(&#34;Gandalf&#34;, 2019);

// Kotest
fellowshipOfTheRing.shouldHaveSize(9)
wizard shouldBe Wizard(
    name = &#34;Gandalf&#34;,
    age = 2019,
)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The latter reads much more naturally due to Kotlin&amp;#8217;s language features.
I imagine even a non-coder could easily understand it.
Way cooler, right?
Well, not so much if you only quickly scan the generated test classes anyway&amp;hellip;
I could continue to give examples, but I think my point is clear.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;There is one thing I must mention, though.
One could say: let&amp;#8217;s just not use AI.
But even if we disregard the corporate push for AI, I already notice that I don&amp;#8217;t want to go back to the way things were.
Having AI quickly scan and summarize what a system is doing, write code at lightning speed, generate visuals for presentations, create a bunch of Jira stories, and even help improve this very blog post is just too handy!
Yet, I still feel that craftsmanship and skill are slowly being replaced by a general slop.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Is the future of software engineering bleak then?
I guess it depends on who&amp;#8217;s asking.
Those who really love the coding itself—syntax and all—would probably answer with a tentative &#34;yes&#34;.
For others who love the business side much more than the actual coding, it would be a &#34;no&#34;.
Or maybe a &#34;not yet&#34;.
The problem here is that AI is changing the world so fast that we cannot predict its future very well.
There have been some attempts, like &lt;a href=&#34;https://ai-2027.com&#34;&gt;AI 2027&lt;/a&gt; and &lt;a href=&#34;https://europe2031.ai&#34;&gt;Europe 2031&lt;/a&gt;, but both have a negative bias to begin with&lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_2&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_2&#34; title=&#34;View footnote.&#34;&gt;2&lt;/a&gt;]&lt;/sup&gt;.
Furthermore, these reports look at the industry as a whole.
For an individual engineer, this question should be asked on a more personal level: &#34;Do I still love my job, now that it is changing into something else? And what do I have to do to keep up?&#34;&lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_3&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_3&#34; title=&#34;View footnote.&#34;&gt;3&lt;/a&gt;]&lt;/sup&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;To be honest, that&amp;#8217;s where I am stuck right now.
There is no definitive guide or source out there to help with this question.
We can look back at history to see how people reacted to previous major shifts.
To name just the most important: the mastery of fire, the origin of language, the dawn of agriculture, the invention of the wheel, writing, the rise of religion, the invention of the printing press, the coming of the Industrial Revolution, electricity, and, later on, the digital revolution.
While these events occurred in increasingly rapid succession, a common pattern emerges for those we have records of: people in all ages have responded to transformative technologies with a mix of excitement, fear, skepticism, and adaptation&lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_4&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_4&#34; title=&#34;View footnote.&#34;&gt;4&lt;/a&gt;]&lt;/sup&gt;.
The same applies to our current age.
A 2018 study &lt;a href=&#34;https://www.pewresearch.org/internet/2018/12/10/artificial-intelligence-and-the-future-of-humans/&#34;&gt;Artificial Intelligence and the Future of Humans&lt;/a&gt; showed that 63% believed people would be better off with advanced AI, while 37% believed they would not&lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_5&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_5&#34; title=&#34;View footnote.&#34;&gt;5&lt;/a&gt;]&lt;/sup&gt;.
So where does that leave us?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;For me, this is an ongoing struggle.
That&amp;#8217;s also why I wrote this post: I have a feeling this sentiment is shared by many more people in our field than it might seem.
The internet is flooded with AI enthusiasm.
On the other extreme, some are fiercely against the use of AI.
But for most of us, we&amp;#8217;ve simply been thrown into it, whether we like it or not.
So, at the very least, I suggest we start talking about it!
Don&amp;#8217;t hesitate to voice your discomfort.
And while doing so, try to ride the waves of AI as best as you can.
Or at least, that&amp;#8217;s what I&amp;#8217;ve been trying to do.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;To end this post, let&amp;#8217;s get back to the quote I started with.
Real Tolkien fans know it&amp;#8217;s actually an adapted quote from Treebeard in the book &#34;The Return of the King&#34;.
Still, I chose the film version because of that final line: &#34;for none now live who remember it&#34;.
Perhaps that&amp;#8217;s where we are headed, our job slowly fading into something else until it no longer exists.
Well, if that&amp;#8217;s the case, let&amp;#8217;s enjoy it while we can.
And maybe, one day, we can tell our grandchildren about the days when we programmed the machines ourselves.
Now that would be a tale to tell!&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;footnotes&#34;&gt;
&lt;hr&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_1&#34;&gt;
&lt;a href=&#34;#_footnoteref_1&#34;&gt;1&lt;/a&gt;. AIs tend to generate the most common implementations simply because their training data contains more of those patterns. That&amp;#8217;s also why they are still much better at writing Java code than generating the underlying bytecode.
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_2&#34;&gt;
&lt;a href=&#34;#_footnoteref_2&#34;&gt;2&lt;/a&gt;. If you prefer narrative scenarios, I recommend reading &lt;a href=&#34;https://babuschk.in/posts/2026-01-25-life-on-claude-nine.html&#34;&gt;Life on Claude Nine&lt;/a&gt; by Igor Babuschkin. It has also been wonderfully adapted into the animated video: &lt;a href=&#34;https://www.youtube.com/watch?v=S2oIFOm-XXQ&#34;&gt;72-Hour AI Takeover: A Realistic Scenario&lt;/a&gt;.
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_3&#34;&gt;
&lt;a href=&#34;#_footnoteref_3&#34;&gt;3&lt;/a&gt;. Though it is outside the scope of this blog, it is interesting to note the reverse-shift: non-coders entering the software engineering field through vibe-coding and gradually becoming interested in the underlying code. See &lt;a href=&#34;https://www.xda-developers.com/used-vibe-coding-to-learn-programming-worked-better-than-any-course/&#34;&gt;I used vibe-coding to actually learn programming, and it worked better than any course&lt;/a&gt; for an example.
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_4&#34;&gt;
&lt;a href=&#34;#_footnoteref_4&#34;&gt;4&lt;/a&gt;. You might not expect it, but it is surprisingly hard to find papers supporting this claim. Though they do not really prove my point, the subject is touched upon by &lt;a href=&#34;https://pmc.ncbi.nlm.nih.gov/articles/PMC7477771/pdf/10.1177_1745691620919372.pdf&#34;&gt;The Sisyphean Cycle of Technology Panics&lt;/a&gt;, &lt;a href=&#34;https://www.iris.sssup.it/bitstream/11382/532952/1/EIST_industrial_revolutions.pdf&#34;&gt;Understanding successive industrial revolutions: A “development block” approach&lt;/a&gt;, and &lt;a href=&#34;https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2353624&#34;&gt;Long waves of technological innovations&lt;/a&gt;.
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_5&#34;&gt;
&lt;a href=&#34;#_footnoteref_5&#34;&gt;5&lt;/a&gt;. Note that this research was conducted before the widespread use of LLMs; I wonder what these numbers would be right now!
&lt;/div&gt;
&lt;/div&gt;</content>
        <category term="AI" scheme="https://jdriven.com/blog/category/AI/" />
        <category term="Future" scheme="https://jdriven.com/blog/tag/Future/" />
        <category term="Change" scheme="https://jdriven.com/blog/tag/Change/" />
    </entry>
    <entry>
        <id>https://jdriven.com/blog/2026/06/Kotlin-Kandy-Get-Text-Before-Or-After-A-Delimiter/</id>
        <title>Kotlin Kandy: Get Text Before Or After A Delimiter</title>
        <social:hashtags>#Kotlin #KotlinKandy</social:hashtags>
        <link rel="alternate" href="https://jdriven.com/blog/2026/06/Kotlin-Kandy-Get-Text-Before-Or-After-A-Delimiter/"/>
        <published>2026-06-09T04:15:09.000Z</published>
        <updated>2026-06-09T04:15:09.000Z</updated>
        <author>
            <name>mrhaki</name>
            <social:mastodon>mrhaki@mastodon.online</social:mastodon>
            <social:bluesky>mrhaki.com</social:bluesky>
            <uri>https://jdriven.com/blog/author/mrhaki</uri>
        </author>
        <summary type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Kotlin adds the &lt;code&gt;substringBefore&lt;/code&gt;, &lt;code&gt;substringBeforeLast&lt;/code&gt;, &lt;code&gt;substringAfter&lt;/code&gt; and &lt;code&gt;substringAfterLast&lt;/code&gt; extension functions to the &lt;code&gt;String&lt;/code&gt; class. Instead of using indices to get a substring you can use a string or character value. The functions without &lt;code&gt;Last&lt;/code&gt; use the first occurrence of the delimiter and the methods with &lt;code&gt;Last&lt;/code&gt; use the last occurrence. If the delimiter is not found the original string is returned. You can supply a value that should be returned when the delimiter is not found.&lt;/p&gt;
&lt;/div&gt;</summary>
        <content type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Kotlin adds the &lt;code&gt;substringBefore&lt;/code&gt;, &lt;code&gt;substringBeforeLast&lt;/code&gt;, &lt;code&gt;substringAfter&lt;/code&gt; and &lt;code&gt;substringAfterLast&lt;/code&gt; extension functions to the &lt;code&gt;String&lt;/code&gt; class. Instead of using indices to get a substring you can use a string or character value. The functions without &lt;code&gt;Last&lt;/code&gt; use the first occurrence of the delimiter and the methods with &lt;code&gt;Last&lt;/code&gt; use the last occurrence. If the delimiter is not found the original string is returned. You can supply a value that should be returned when the delimiter is not found.&lt;/p&gt;
&lt;/div&gt;
&lt;span id=&#34;more&#34;&gt;&lt;/span&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The following example code uses the extension functions in several use cases:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-kotlin hljs&#34; data-lang=&#34;kotlin&#34;&gt;val s = &#34;Kotlin Kandy Blogpost&#34;

// Get the substring after a given delimiter character.
assert(s.substringAfter(delimiter = &#39; &#39;) == &#34;Kandy Blogpost&#34;)
// Get the substring after a given delimiter string.
assert(s.substringAfter(&#34;Kotlin &#34;) == &#34;Kandy Blogpost&#34;)

// When the delimiter is not found the original string is returned.
assert(s.substringAfter(delimiter = &#39;!&#39;) == &#34;Kotlin Kandy Blogpost&#34;)

// Use a second argument that should be returned if
// the delimiter is not found.
assert(s.substringAfter(delimiter = &#39;!&#39;, missingDelimiterValue = &#34;not found&#34;) == &#34;not found&#34;)
assert(s.substringAfter(&#34;Java&#34;, &#34;Joy&#34;) == &#34;Joy&#34;)

// If delimiter appears more than once using substringAfterLast
// will return the value after the last occurrence of the delimiter.
assert(s.substringAfterLast(delimiter = &#39; &#39;) == &#34;Blogpost&#34;)


// Get the substring before a given delimiter character.
assert(s.substringBefore(delimiter = &#39; &#39;) == &#34;Kotlin&#34;)
// Get substring before a given delimiter string.
assert(s.substringBefore(&#34;Kandy&#34;) == &#34;Kotlin &#34;)

// When the delimiter is not found the original string is returned.
assert(s.substringBefore(delimiter = &#39;!&#39;) == &#34;Kotlin Kandy Blogpost&#34;)

// Use a second argument that should be returned if
// the delimiter is not found.
assert(s.substringBefore(&#39;@&#39;, missingDelimiterValue = &#34;not found&#34;) == &#34;not found&#34;)

// If delimiter appears more than once using substringBeforeLast
// will return the value before the last occurrence of the delimiter.
assert(s.substringBeforeLast(delimiter = &#39; &#39;) == &#34;Kotlin Kandy&#34;)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Written with Kotlin 2.3.20.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://blog.mrhaki.com/2026/04/kotlin-kandy-get-text-before-or-after.html&#34;&gt;Original post&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;</content>
        <category term="Kotlin" scheme="https://jdriven.com/blog/category/Kotlin/" />
        <category term="Kotlin" scheme="https://jdriven.com/blog/tag/Kotlin/" />
        <category term="Kotlin Kandy" scheme="https://jdriven.com/blog/tag/Kotlin-Kandy/" />
    </entry>
    <entry>
        <id>https://jdriven.com/blog/2026/05/Kotlin-Kandy-Get-A-Random-Element-From-A-Collection/</id>
        <title>Kotlin Kandy: Get A Random Element From A Collection</title>
        <social:hashtags>#KotlinKandy</social:hashtags>
        <link rel="alternate" href="https://jdriven.com/blog/2026/05/Kotlin-Kandy-Get-A-Random-Element-From-A-Collection/"/>
        <published>2026-05-19T04:17:27.000Z</published>
        <updated>2026-05-19T04:17:27.000Z</updated>
        <author>
            <name>mrhaki</name>
            <social:mastodon>mrhaki@mastodon.online</social:mastodon>
            <social:bluesky>mrhaki.com</social:bluesky>
            <uri>https://jdriven.com/blog/author/mrhaki</uri>
        </author>
        <summary type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Kotlin has very useful extensions functions for working with collections. These extension functions make working with collections more easy and fun. One of the extension functions is the &lt;code&gt;random&lt;/code&gt; function. When you call &lt;code&gt;random()&lt;/code&gt; Kotlin returns a single element from the collection using the default random source. The function also accepts a &lt;code&gt;Random&lt;/code&gt; instance as argument. This instance has a seeded value to return repeatable random values.&lt;/p&gt;
&lt;/div&gt;</summary>
        <content type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Kotlin has very useful extensions functions for working with collections. These extension functions make working with collections more easy and fun. One of the extension functions is the &lt;code&gt;random&lt;/code&gt; function. When you call &lt;code&gt;random()&lt;/code&gt; Kotlin returns a single element from the collection using the default random source. The function also accepts a &lt;code&gt;Random&lt;/code&gt; instance as argument. This instance has a seeded value to return repeatable random values.&lt;/p&gt;
&lt;/div&gt;
&lt;span id=&#34;more&#34;&gt;&lt;/span&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In the following example you can see different ways to use &lt;code&gt;random&lt;/code&gt; on collections:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-kotlin hljs&#34; data-lang=&#34;kotlin&#34;&gt;import kotlin.random.Random

val languages = listOf(&#34;Kotlin&#34;, &#34;Groovy&#34;, &#34;Java&#34;, &#34;Scala&#34;)

// Calling random() without arguments uses the default random source.
val language = languages.random()
assert(language in languages)


// When you use the same seed you get the same result.
assert(languages.random(Random(42)) == &#34;Kotlin&#34;)
assert(languages.random(Random(42)) == &#34;Kotlin&#34;)


// Reusing the same Random instance gives you a repeatable sequence
// of random values.
val randomLanguages = Random(123)
val picks = List(5) { languages.random(randomLanguages) }

assert(picks == listOf(&#34;Kotlin&#34;, &#34;Groovy&#34;, &#34;Scala&#34;, &#34;Groovy&#34;, &#34;Kotlin&#34;))


// A Set is also a collection, so random works here as well.
val colors = setOf(&#34;red&#34;, &#34;green&#34;, &#34;blue&#34;, &#34;yellow&#34;)
assert(colors.random(Random(42)) == &#34;red&#34;)


// You can also use random on Map.entries.
val tools = mapOf(
    &#34;build&#34; to &#34;Gradle&#34;,
    &#34;http&#34; to &#34;Ktor&#34;
)

assert(tools.entries.random(Random(42)).toPair() == (&#34;build&#34; to &#34;Gradle&#34;))


// Calling random() on an empty collection throws a NoSuchElementException.
val failure = runCatching { emptyList&amp;lt;String&amp;gt;().random() }
assert(failure.exceptionOrNull() is NoSuchElementException)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Written with Kotlin 2.3.20.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://blog.mrhaki.com/2026/04/kotlin-kandy-get-random-element-from.html&#34;&gt;Original post&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;</content>
        <category term="Kotlin" scheme="https://jdriven.com/blog/category/Kotlin/" />
        <category term="Kotlin Kandy" scheme="https://jdriven.com/blog/tag/Kotlin-Kandy/" />
    </entry>
    <entry>
        <id>https://jdriven.com/blog/2026/05/Event-System-breaking-down-the-basics/</id>
        <title>Event System: Breaking Down the Basics</title>
        <social:hashtags>#Java #Spring</social:hashtags>
        <link rel="alternate" href="https://jdriven.com/blog/2026/05/Event-System-breaking-down-the-basics/"/>
        <published>2026-05-15T05:00:00.000Z</published>
        <updated>2026-05-15T05:00:00.000Z</updated>
        <author>
            <name>Jacob</name>
            <uri>https://jdriven.com/blog/author/jacobvlingen</uri>
        </author>
        <summary type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Jim is a guy who never stops exploring.
A couple of years ago, he dove into &lt;a href=&#34;https://jdriven.com/blog/2023/07/Annotation-based-Dependency-Injection-Breaking-Down-the-Basics&#34;&gt;dependency injection&lt;/a&gt;.
But now, all of a sudden, something else hit him.
Event systems are pretty common these days.
As a Spring guy, he&amp;#8217;s been using events for ages, but now he feels the need to know how they actually work under the hood.
So, how do they actually work?&lt;/p&gt;
&lt;/div&gt;</summary>
        <content type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Jim is a guy who never stops exploring.
A couple of years ago, he dove into &lt;a href=&#34;https://jdriven.com/blog/2023/07/Annotation-based-Dependency-Injection-Breaking-Down-the-Basics&#34;&gt;dependency injection&lt;/a&gt;.
But now, all of a sudden, something else hit him.
Event systems are pretty common these days.
As a Spring guy, he&amp;#8217;s been using events for ages, but now he feels the need to know how they actually work under the hood.
So, how do they actually work?&lt;/p&gt;
&lt;/div&gt;
&lt;span id=&#34;more&#34;&gt;&lt;/span&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;IYKYK&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I assume as a reader you are familiar with these event systems as well.
But to be sure, let&amp;#8217;s show a simple example.
Spring automatically wires up an &lt;code&gt;ApplicationEventPublisher&lt;/code&gt; bean, which you can use to send events:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-java hljs&#34; data-lang=&#34;java&#34;&gt;@Service
@RequiredArgsConstructor
public class OrderService {
    private final ApplicationEventPublisher publisher;

    public void placeOrder(String orderId) {
        // business logic
        publisher.publishEvent(new OrderPlacedEvent(orderId));
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Listening to them is as easy as&lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_1&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_1&#34; title=&#34;View footnote.&#34;&gt;1&lt;/a&gt;]&lt;/sup&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-java hljs&#34; data-lang=&#34;java&#34;&gt;@Component
public class OrderPlacedListener {
    @EventListener
    public void onOrderPlaced(OrderPlacedEvent event) {
        System.out.println(&#34;Order placed: &#34; + event.orderId());
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;Understanding requires insight. Insight must be anchored.&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;You can find this information in the &lt;a href=&#34;https://docs.spring.io/spring-framework/reference/core/beans/context-introduction.html&#34;&gt;documentation&lt;/a&gt;, of course.
But the actual question remains: how does this work?
If you think about it, it&amp;#8217;s actually way easier than you might expect, because there are only two things going on:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Components can send events&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Components can listen to events&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;To make it work, you need another component that bridges the two.
Basically, a component where other components can register their methods as event listeners.
Then, when an event is published, all matching listener methods are invoked.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The most basic implementation could look something like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-java hljs&#34; data-lang=&#34;java&#34;&gt;@Component
public class EventBus {
   private final List&amp;lt;EventListenerInvoker&amp;gt; invokers = new ArrayList&amp;lt;&amp;gt;();

   public void register(Object bean, Method eventListener) {
       invokers.add(new EventListenerInvoker(bean, eventListener));
   }

   public void publish(Object event) {
       invokers.forEach(it -&amp;gt; it.invoke(event));
   }

   private record EventListenerInvoker(Object bean, Method eventListener) {
       @SneakyThrows
       void invoke(Object event) {
           // Check if the event type matches the first parameter of the listener method
           if (eventListener.getParameterTypes()[0].isAssignableFrom(event.getClass())) {
               eventListener.invoke(bean, event);
           }
       }
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;And then you need a mechanism to loop over all your beans to register them as event listeners (reusing the &lt;code&gt;initializedBeans&lt;/code&gt; from our previous DI exploration):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-java hljs&#34; data-lang=&#34;java&#34;&gt;for (Object bean : initializedBeans.values()) {
    for (Method method : bean.getClass().getDeclaredMethods()) {
        if (method.isAnnotationPresent(EventListener.class)) {
            eventBus.register(bean, method);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;That&amp;#8217;s all there is to it.
It&amp;#8217;s that simple!
Of course, you can improve this by supporting multiple event handlers per method, adding a &lt;code&gt;Map&lt;/code&gt; to cache listeners by event type for better performance, or using an &lt;code&gt;ExecutorService&lt;/code&gt; to make it asynchronous.
If you want to see the full implementation, check out the updated example &lt;a href=&#34;https://github.com/jevanlingen/MiniFramework&#34;&gt;here&lt;/a&gt;!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;footnotes&#34;&gt;
&lt;hr&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_1&#34;&gt;
&lt;a href=&#34;#_footnoteref_1&#34;&gt;1&lt;/a&gt;. By default, Spring events are synchronous. If you need asynchronous behavior, you need to &lt;code&gt;@EnableAsync&lt;/code&gt; and use the &lt;code&gt;@Async&lt;/code&gt; annotation next to the &lt;code&gt;@EventListener&lt;/code&gt; annotation.
&lt;/div&gt;
&lt;/div&gt;</content>
        <category term="Event System" scheme="https://jdriven.com/blog/category/Event-System/" />
        <category term="Java" scheme="https://jdriven.com/blog/tag/Java/" />
        <category term="Spring" scheme="https://jdriven.com/blog/tag/Spring/" />
    </entry>
    <entry>
        <id>https://jdriven.com/blog/2026/05/Kotlin-Kandy-Transform-Map-Keys-Or-Values-With-mapKeys-And-mapValues/</id>
        <title>Kotlin Kandy: Transform Map Keys Or Values With mapKeys And mapValues</title>
        <social:hashtags>#KotlinKandy</social:hashtags>
        <link rel="alternate" href="https://jdriven.com/blog/2026/05/Kotlin-Kandy-Transform-Map-Keys-Or-Values-With-mapKeys-And-mapValues/"/>
        <published>2026-05-12T04:04:38.000Z</published>
        <updated>2026-05-12T04:04:38.000Z</updated>
        <author>
            <name>mrhaki</name>
            <social:mastodon>mrhaki@mastodon.online</social:mastodon>
            <social:bluesky>mrhaki.com</social:bluesky>
            <uri>https://jdriven.com/blog/author/mrhaki</uri>
        </author>
        <summary type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Sometimes you want to transform only the keys in a &lt;code&gt;Map&lt;/code&gt;, or only transform the values. Kotlin has two useful methods to achieve this: &lt;code&gt;mapKeys&lt;/code&gt; and &lt;code&gt;mapValues&lt;/code&gt;. You can use &lt;code&gt;mapKeys&lt;/code&gt; to transform the keys of the map while keeping the values the same. With &lt;code&gt;mapValues&lt;/code&gt; you can transform the values of the map while keeping the keys the same. Both methods accept a lambda function as asrgument of type &lt;code&gt;Map.Entry&lt;/code&gt; and must return the new key or value. In order to transform the keys or values and add the result to an existing &lt;code&gt;Map&lt;/code&gt; you can use the methods &lt;code&gt;mapKeysTo&lt;/code&gt; and &lt;code&gt;mapValuesTo&lt;/code&gt;. The first argument is the existing (mutable) &lt;code&gt;Map&lt;/code&gt; and the second argument is the lambda function.&lt;/p&gt;
&lt;/div&gt;</summary>
        <content type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Sometimes you want to transform only the keys in a &lt;code&gt;Map&lt;/code&gt;, or only transform the values. Kotlin has two useful methods to achieve this: &lt;code&gt;mapKeys&lt;/code&gt; and &lt;code&gt;mapValues&lt;/code&gt;. You can use &lt;code&gt;mapKeys&lt;/code&gt; to transform the keys of the map while keeping the values the same. With &lt;code&gt;mapValues&lt;/code&gt; you can transform the values of the map while keeping the keys the same. Both methods accept a lambda function as asrgument of type &lt;code&gt;Map.Entry&lt;/code&gt; and must return the new key or value. In order to transform the keys or values and add the result to an existing &lt;code&gt;Map&lt;/code&gt; you can use the methods &lt;code&gt;mapKeysTo&lt;/code&gt; and &lt;code&gt;mapValuesTo&lt;/code&gt;. The first argument is the existing (mutable) &lt;code&gt;Map&lt;/code&gt; and the second argument is the lambda function.&lt;/p&gt;
&lt;/div&gt;
&lt;span id=&#34;more&#34;&gt;&lt;/span&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In the following example we use &lt;code&gt;mapKeys&lt;/code&gt; to transform the keys of a map:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-kotlin hljs&#34; data-lang=&#34;kotlin&#34;&gt;// Sample map with language names as keys and their first release year as values.
val languages = mapOf(&#34;Kotlin&#34; to 2011, &#34;Groovy&#34; to 2003, &#34;Java&#34; to 1995)

// Use mapKeys to transform the keys to lowercase.
// The lambda receives a Map.Entry with key and value properties.
assert(languages.mapKeys { it.key.lowercase() } ==
         mapOf(&#34;kotlin&#34; to 2011, &#34;groovy&#34; to 2003, &#34;java&#34; to 1995))

// You can use destructuring in the lambda to access key and value directly.
assert(languages.mapKeys { (key, _) -&amp;gt; key.uppercase() } ==
         mapOf(&#34;KOTLIN&#34; to 2011, &#34;GROOVY&#34; to 2003, &#34;JAVA&#34; to 1995))

// You can also use the value property in the lambda
// to create a new key based on the value.
assert(languages.mapKeys { &#34;${it.key} (${it.value})&#34; } ==
         mapOf(&#34;Kotlin (2011)&#34; to 2011, &#34;Groovy (2003)&#34; to 2003, &#34;Java (1995)&#34; to 1995))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In the next example we use &lt;code&gt;mapValues&lt;/code&gt; to transform the values of a map:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-kotlin hljs&#34; data-lang=&#34;kotlin&#34;&gt;val languages = mapOf(&#34;Kotlin&#34; to 2011, &#34;Groovy&#34; to 2003, &#34;Java&#34; to 1995)

// Use mapValues to transform the values.
// Calculate the age of the language.
assert(languages.mapValues { 2026 - it.value } ==
         mapOf(&#34;Kotlin&#34; to 15, &#34;Groovy&#34; to 23, &#34;Java&#34; to 31))

// Using destructuring in the lambda to access key and value directly.
assert(languages.mapValues { (_, value) -&amp;gt; value * 2 } ==
         mapOf(&#34;Kotlin&#34; to 4022, &#34;Groovy&#34; to 4006, &#34;Java&#34; to 3990))

// You can also use the key property to create a new value
// based on both the key and value.
assert(languages.mapValues { &#34;${it.key} was first released in ${it.value}&#34; } ==
         mapOf(&#34;Kotlin&#34; to &#34;Kotlin was first released in 2011&#34;,
               &#34;Groovy&#34; to &#34;Groovy was first released in 2003&#34;,
               &#34;Java&#34; to &#34;Java was first released in 1995&#34;))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;We can also use the methods &lt;code&gt;mapKeysTo&lt;/code&gt; and &lt;code&gt;mapValuesTo&lt;/code&gt; to add the transformed entries to an existing mutable &lt;code&gt;Map&lt;/code&gt; instance. The first argument is the mutable &lt;code&gt;Map&lt;/code&gt; and the second argument is the lambda function to transform the key or value:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-kotlin hljs&#34; data-lang=&#34;kotlin&#34;&gt;val languages = mapOf(&#34;Kotlin&#34; to 2011, &#34;Groovy&#34; to 2003)

// Use mapKeysTo to add transformed entries to an existing mutable map.
val result = languages.mapKeysTo(mutableMapOf(&#34;java&#34; to 1995)) { it.key.lowercase() }

assert(result == mapOf(&#34;java&#34; to 1995, &#34;kotlin&#34; to 2011, &#34;groovy&#34; to 2003))

// Use mapValuesTo to add transformed entries to an existing mutable map.
val ageResult = languages.mapValuesTo(mutableMapOf(&#34;Java&#34; to 31)) { 2026 - it.value }

assert(ageResult == mapOf(&#34;Java&#34; to 31, &#34;Kotlin&#34; to 15, &#34;Groovy&#34; to 23))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Written with Kotlin 2.3.20.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://blog.mrhaki.com/2026/04/kotlin-kandy-transform-map-keys-or.html&#34;&gt;Original post&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;</content>
        <category term="Kotlin" scheme="https://jdriven.com/blog/category/Kotlin/" />
        <category term="Kotlin Kandy" scheme="https://jdriven.com/blog/tag/Kotlin-Kandy/" />
    </entry>
    <entry>
        <id>https://jdriven.com/blog/2026/05/Nushell-Niceties-Wrapping-External-Commands-With-def---wrapped/</id>
        <title>Nushell Niceties: Wrapping External Commands With def --wrapped</title>
        <social:hashtags>#Nushell</social:hashtags>
        <link rel="alternate" href="https://jdriven.com/blog/2026/05/Nushell-Niceties-Wrapping-External-Commands-With-def---wrapped/"/>
        <published>2026-05-06T04:52:23.000Z</published>
        <updated>2026-05-06T04:52:23.000Z</updated>
        <author>
            <name>mrhaki</name>
            <social:mastodon>mrhaki@mastodon.online</social:mastodon>
            <social:bluesky>mrhaki.com</social:bluesky>
            <uri>https://jdriven.com/blog/author/mrhaki</uri>
        </author>
        <summary type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The &lt;code&gt;def&lt;/code&gt; keyword in Nushell is used to define a custom command. By adding the &lt;code&gt;--wrapped&lt;/code&gt; flag you can tell Nushell to accept unknown flags and arguments and pass them on as strings. In the command parameters you use a &#34;rest&#34; parameter defined by &lt;code&gt;…​&lt;/code&gt; to capture the remaining arguments. Then in the command body you use the spread operator &lt;code&gt;…​&lt;/code&gt; to expand them again. This is very useful when you want to create a small wrapper around an external command with lots of options, but without having to define all those options yourself.&lt;/p&gt;
&lt;/div&gt;</summary>
        <content type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The &lt;code&gt;def&lt;/code&gt; keyword in Nushell is used to define a custom command. By adding the &lt;code&gt;--wrapped&lt;/code&gt; flag you can tell Nushell to accept unknown flags and arguments and pass them on as strings. In the command parameters you use a &#34;rest&#34; parameter defined by &lt;code&gt;…​&lt;/code&gt; to capture the remaining arguments. Then in the command body you use the spread operator &lt;code&gt;…​&lt;/code&gt; to expand them again. This is very useful when you want to create a small wrapper around an external command with lots of options, but without having to define all those options yourself.&lt;/p&gt;
&lt;/div&gt;
&lt;span id=&#34;more&#34;&gt;&lt;/span&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In the following example you see how this can be used to wrap the external command &lt;code&gt;kubectl&lt;/code&gt; in a custom command with the name &lt;code&gt;k&lt;/code&gt;. You can define the following wrapper command:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-nu hljs&#34; data-lang=&#34;nu&#34;&gt;# Define custom command k with --wrapped option.
def --wrapped k [...rest] {
    # Forward all arguments passed to the this command
    # to the kubectl command.
    # Add extra -o json argument so the output is JSON.
    # Use from json to parse the JSON into Nushell data structure,
    # so you can use default Nushell commands for querying, selecting
    # and more.
    ^kubectl ...$rest -o json | from json
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The following example shows how the custom &lt;code&gt;k&lt;/code&gt; command can be used to query the JSON output using Nushell commands:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-nu hljs&#34; data-lang=&#34;nu&#34;&gt;&amp;gt; k get pod api-7d9b6c7f9d-abcde -n demo
    | select metadata.name status.phase spec.nodeName
╭───────────────┬──────────────────────╮
│ metadata.name │ api-7d9b6c7f9d-abcde │
│ status.phase  │ Running              │
│ spec.nodeName │ worker-1             │
╰───────────────┴──────────────────────╯

# Using get items for JSON array output.
&amp;gt; k get pods -n demo
    | get items
    | where {|pod| $pod.status.phase in [&#39;Pending&#39;, &#39;Failed&#39;] and $pod.spec.nodeName == &#39;worker-2&#39; }
    | select metadata.name status.phase spec.nodeName metadata.namespace
    | rename pod phase node namespace
╭───┬─────────────────────────┬─────────┬──────────┬───────────╮
│ # │           pod           │  phase  │   node   │ namespace │
├───┼─────────────────────────┼─────────┼──────────┼───────────┤
│ 0 │ worker-5b7d8b9f7f-r2mql │ Pending │ worker-2 │ demo      │
│ 1 │ batch-77c99f88c-hj2lm   │ Failed  │ worker-2 │ demo      │
╰───┴─────────────────────────┴─────────┴──────────┴───────────╯&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Written with Nushell 0.112.2.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://blog.mrhaki.com/2026/04/nushell-niceties-wrapping-external.html&#34;&gt;Original post&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;</content>
        <category term="Nushell" scheme="https://jdriven.com/blog/category/Nushell/" />
        <category term="Nushell" scheme="https://jdriven.com/blog/tag/Nushell/" />
    </entry>
    <entry>
        <id>https://jdriven.com/blog/2026/05/AI-team-dynamics-3/</id>
        <title>AI&#39;s Impact on Team Dynamics (Part 3) Collaboration &amp; Healthy AI Use</title>
        <social:hashtags>#AI #Techradar</social:hashtags>
        <link rel="alternate" href="https://jdriven.com/blog/2026/05/AI-team-dynamics-3/"/>
        <published>2026-05-01T05:56:00.000Z</published>
        <updated>2026-05-01T05:56:00.000Z</updated>
        <author>
            <name>Erik</name>
            <social:mastodon>erikj@mastodon.nl</social:mastodon>
            <uri>https://jdriven.com/blog/author/erik-pronk</uri>
        </author>
        <summary type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In the previous part, I discussed how AI impacts learning and team effectiveness, highlighting the tension between speed and deeper understanding.
While AI offers clear advantages, it also introduces new risks for long-term team health.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In this final part, I focus on how teams can consciously integrate AI while preserving collaboration, psychological safety, and strong team dynamics.&lt;/p&gt;
&lt;/div&gt;</summary>
        <content type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In the previous part, I discussed how AI impacts learning and team effectiveness, highlighting the tension between speed and deeper understanding.
While AI offers clear advantages, it also introduces new risks for long-term team health.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In this final part, I focus on how teams can consciously integrate AI while preserving collaboration, psychological safety, and strong team dynamics.&lt;/p&gt;
&lt;/div&gt;
&lt;span id=&#34;more&#34;&gt;&lt;/span&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;Maintaining psychological safety in the AI era&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Psychological safety, the foundation of effective team dynamics, faces new
challenges in the AI era.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;When developers can generate solutions privately with AI, they&amp;#8217;re less likely to
expose their thinking process to the team. They&amp;#8217;re less likely to admit when they&amp;#8217;re
stuck or uncertain. This personal vulnerability that builds trust gets replaced by a
facade of AI-assisted competence.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I expect this effect to be particularly visible with medior developers. Junior
developers are expected to ask questions, so they face less stigma in seeking help.
Senior developers have already built their network and credibility. But medior
developers occupy an awkward middle ground, they feel pressure to appear
knowledgeable, and AI gives them a way to maintain that appearance without asking
for help. This prevents them from building the deeper relationships that would
actually support their growth.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Teams need to actively cultivate an environment where it&amp;#8217;s safe to say, &#34;I used AI to
create this, but I&amp;#8217;m not sure it&amp;#8217;s the right approach. Can we review it together?&#34; This
requires leadership that models this behavior and explicitly values learning over
appearing knowledgeable.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;Collaboration&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Collaboration is a skill. Like any skill, it requires practice. When developers spend
more time interacting with AI and less time interacting with humans, their
collaboration skills decline.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;They become less adept at explaining their thinking. Less patient with the
unstructured way we as humans use for communication. Less skilled at navigating
disagreements and finding compromise.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The consequences ripple through every aspect of teamwork. Code reviews that used
to spark rich discussions now get perfunctory approvals. Developers assume that if
the code works and AI helped generate it, it must be fine. The critical thinking that
makes code reviews valuable gets bypassed.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Pair programming becomes less common. Why pair when you can just ask AI or pair
program with your personal AI assistant? But pairing isn&amp;#8217;t just about solving problems
faster. It&amp;#8217;s about building shared understanding, transferring knowledge, and
strengthening team bonds.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The result is teams that function more like collections of individuals working in
parallel. Feedback loops between humans diminish instead of strengthening over
time as they do in true collaborative teams.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;Strategies for healthy AI integration&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;So how do we get the benefits of AI without losing the human dynamics that make
teams effective? Here are some of my thoughts:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Establish AI usage criteria as a team. Don&amp;#8217;t let AI adoption happen organically.
Discuss as a team how you want to use these tools. When is AI appropriate? When
should you seek human input instead? Make these criteria explicit, and ensure they
also account for relevant legislation and moral considerations. Ethical and legal
boundaries should guide your decisions just as much as technical convenience.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Use AI as a conversation starter, not a conversation ender. When AI generates a
solution, treat it as a draft to discuss, not a final answer. Ask, &#34;What do we think
about this approach? What are we missing?&#34;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Protect collaboration time. Schedule regular pairing sessions, architecture
discussions, and knowledge-sharing meetings. Make these non-negotiable, even
when AI could theoretically replace them.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Rotate AI-free days. Some teams experiment with days where AI tools are off-limits.
This forces developers to rely on each other and keeps collaboration skills sharp.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Make learning visible. Encourage developers to share what they learned from AI
interactions. &#34;I asked AI about this pattern, and here&amp;#8217;s what I discovered.&#34; This
transforms individual AI usage into collective learning.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Measure what matters. Don&amp;#8217;t just track velocity. Track code quality, knowledge
distribution across the team, and team satisfaction. If AI is improving velocity but
harming these other metrics, adjust your approach.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;The future of team dynamics&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;AI isn&amp;#8217;t going away. If anything, these tools will become more capable and more
integrated into our workflows. The teams that thrive will be those that consciously
shape how AI fits into their dynamics.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;To achieve this requires treating AI integration as a team dynamics challenge, not
just a technical one. It requires ongoing conversation about what we&amp;#8217;re gaining and
what we&amp;#8217;re losing. It requires leadership that values human connection as much as
productivity.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Michael Jordan couldn&amp;#8217;t win championships alone, no matter how talented he was.
The same is true for software teams. AI can make individual developers more
productive, but it can&amp;#8217;t replace the collective intelligence, creativity, and resilience
that emerges from strong team dynamics.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock text-center&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/04/MJ_NoI_web.png&#34; alt=&#34;MJ NoI web&#34; width=&#34;50%&#34;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;AI&amp;#8217;s impact on team dynamics is neither purely positive nor purely negative. It&amp;#8217;s a
powerful tool that amplifies our choices. If we choose isolation and speed over
collaboration and depth, AI will accelerate that path. If we choose to use AI as a
catalyst for better collaboration, it can enhance our team dynamics.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The key is intentionality. We need to actively design how AI fits into our teams, rather
than passively accepting whatever dynamics emerge. We need to protect the human
interactions that make teams effective, even as we embrace the productivity gains AI
offers.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Because at the end of the day, software engineering is still a human journey. The
code we write serves human needs. The systems we build are maintained by human
teams. And the success of our projects depends on human collaboration.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;AI can be a powerful ally in this work. But only if we ensure it enhances, rather than
replaces, the team dynamics that make us effective.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;So as we integrate AI into our workflow, let&amp;#8217;s ask ourselves: Is this making me more
connected to my team, or more isolated? Is this deepening our collective
understanding, or creating individual silos? Is this enhancing our collaboration, or
replacing it?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The answers to these questions will determine whether AI strengthens or weakens
your team dynamics. Choose wisely.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</content>
        <category term="Team Dynamics" scheme="https://jdriven.com/blog/category/Team-Dynamics/" />
        <category term="Tech Culture" scheme="https://jdriven.com/blog/category/Team-Dynamics/Tech-Culture/" />
        <category term="AI" scheme="https://jdriven.com/blog/tag/AI/" />
        <category term="Techradar" scheme="https://jdriven.com/blog/tag/Techradar/" />
    </entry>
    <entry>
        <id>https://jdriven.com/blog/2026/04/AI-team-dynamics-2/</id>
        <title>AI&#39;s Impact on Team Dynamics (Part 2) Learning, Speed &amp; Trade-offs</title>
        <social:hashtags>#AI #Techradar</social:hashtags>
        <link rel="alternate" href="https://jdriven.com/blog/2026/04/AI-team-dynamics-2/"/>
        <published>2026-04-30T05:56:00.000Z</published>
        <updated>2026-04-30T05:56:00.000Z</updated>
        <author>
            <name>Erik</name>
            <social:mastodon>erikj@mastodon.nl</social:mastodon>
            <uri>https://jdriven.com/blog/author/erik-pronk</uri>
        </author>
        <summary type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In part one, I explored how AI is subtly changing team dynamics through isolation and echo chamber effects.
While AI makes individual developers more productive, it can also reduce the natural collaboration that strengthens teams.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In this part, we take a closer look at what this means for learning, knowledge transfer, and the balance between speed and depth in software development.&lt;/p&gt;
&lt;/div&gt;</summary>
        <content type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In part one, I explored how AI is subtly changing team dynamics through isolation and echo chamber effects.
While AI makes individual developers more productive, it can also reduce the natural collaboration that strengthens teams.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In this part, we take a closer look at what this means for learning, knowledge transfer, and the balance between speed and depth in software development.&lt;/p&gt;
&lt;/div&gt;
&lt;span id=&#34;more&#34;&gt;&lt;/span&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;The knowledge transfer crisis&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;One of the most underappreciated aspects of team dynamics is knowledge transfer.
When a junior developer pairs with a senior developer, they&amp;#8217;re not just solving a
problem together. They&amp;#8217;re building a mentorship relationship where years of
experience, judgment calls, and professional wisdom get transferred. Not just code
patterns, but how to think about problems, when to ask for help, and how to navigate
uncertainty.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;AI disrupts this natural knowledge flow. Junior developers can now generate working
code without understanding the underlying principles. They can solve problems
without learning why those problems existed in the first place.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I&amp;#8217;m not suggesting we should make things artificially difficult. But there&amp;#8217;s a difference
between using AI as a learning accelerator and using it as a replacement for
learning. When developers rely on AI without building their own understanding, they
become dependent or, even worse, addicted to AI. They can&amp;#8217;t debug effectively.
They can&amp;#8217;t adapt when requirements change. They can&amp;#8217;t mentor the next generation.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The team&amp;#8217;s collective knowledge, that shared understanding that makes experienced
teams so effective, starts to erode.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;But it&amp;#8217;s not all negative&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Let me be clear: I&amp;#8217;m not anti-AI. Far from it. AI tools have great benefits for team
dynamics when used thoughtfully. And I believe we are at a tipping point in the
history of software engineering. Like Werner Vogels put it in his keynote at AWS
re:Invent, it&amp;#8217;s the dawn of something new, the renaissance developer.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;AI can handle the tedious work that drains energy and motivation. Boilerplate code
or repetitive refactoring and not forgetting documentation generation. By automating
these tasks, AI frees up mental space for the creative, collaborative work that we as
humans excel at.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I&amp;#8217;ve seen teams use AI to level the playing field. Developers who struggle with
English as a second language can use AI to help articulate their ideas more clearly.
Introverted team members who find real-time discussions challenging can use AI to
prepare their thoughts before meetings. In both cases, AI removes barriers that have
nothing to do with technical ability, ensuring that good ideas get heard regardless of
who voices them.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;AI can also serve as a catalyst for discussion. Instead of one person proposing a
solution, a team can ask AI to generate multiple approaches, then discuss the
trade-offs together. This shifts the conversation from &#34;my idea versus yours&#34; to
&#34;which of these options best fits our needs?&#34;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;When a team uses AI as a shared tool rather than individual aid, it can enhance
collaboration.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;The speed versus depth trade-off&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;AI enables incredible speed. Features that used to take days can now be built in
minutes. But speed isn&amp;#8217;t always what teams need.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Software development is as much about understanding the problem as solving it. It&amp;#8217;s
about exploring different approaches. It&amp;#8217;s about building shared context so the team
can maintain and evolve the system over time.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;When teams optimize purely for speed, they sacrifice depth. They ship features
faster but accumulate technical debt. They solve immediate problems but miss
opportunities for systemic improvements.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I&amp;#8217;ve seen teams that became addicted to AI-assisted velocity. Their sprint velocity
looked impressive on paper, but they sacrificed code quality and introduced security
vulnerabilities.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The teams that succeed with AI are those that consciously balance speed with
depth. They use AI to accelerate the straightforward parts, then invest the time
saved into deeper discussions about architecture, design, and long-term
sustainability.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock text-center&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/04/Speed_vs_depth_web.png&#34; alt=&#34;Speed vs depth web&#34; width=&#34;50%&#34;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Next in this series: how to maintain psychological safety, collaboration, and healthy AI usage within teams.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</content>
        <category term="Team Dynamics" scheme="https://jdriven.com/blog/category/Team-Dynamics/" />
        <category term="Tech Culture" scheme="https://jdriven.com/blog/category/Team-Dynamics/Tech-Culture/" />
        <category term="AI" scheme="https://jdriven.com/blog/tag/AI/" />
        <category term="Techradar" scheme="https://jdriven.com/blog/tag/Techradar/" />
    </entry>
    <entry>
        <id>https://jdriven.com/blog/2026/04/AI-team-dynamics-1/</id>
        <title>AI&#39;s Impact on Team Dynamics (Part 1) Isolation &amp; Echo Chambers</title>
        <social:hashtags>#AI #Techradar</social:hashtags>
        <link rel="alternate" href="https://jdriven.com/blog/2026/04/AI-team-dynamics-1/"/>
        <published>2026-04-29T05:56:00.000Z</published>
        <updated>2026-04-29T05:56:00.000Z</updated>
        <author>
            <name>Erik</name>
            <social:mastodon>erikj@mastodon.nl</social:mastodon>
            <uri>https://jdriven.com/blog/author/erik-pronk</uri>
        </author>
        <summary type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;This blog kicks off a three-part series based on my article “AI’s Impact on Team Dynamics,” originally published in a special edition of JavaPro magazine for JCON Europe 2026, titled &lt;strong&gt;Java in the Age of AI&lt;/strong&gt;.
You can find the &lt;a href=&#34;https://javapro.io/magazine-issues/&#34;&gt;full magazine here&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In this first part, I explore how AI is already reshaping the way we collaborate as teams and the less visible effects that come with it.&lt;/p&gt;
&lt;/div&gt;</summary>
        <content type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;This blog kicks off a three-part series based on my article “AI’s Impact on Team Dynamics,” originally published in a special edition of JavaPro magazine for JCON Europe 2026, titled &lt;strong&gt;Java in the Age of AI&lt;/strong&gt;.
You can find the &lt;a href=&#34;https://javapro.io/magazine-issues/&#34;&gt;full magazine here&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In this first part, I explore how AI is already reshaping the way we collaborate as teams and the less visible effects that come with it.&lt;/p&gt;
&lt;/div&gt;
&lt;span id=&#34;more&#34;&gt;&lt;/span&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;AI&amp;#8217;s impact on Team Dynamics&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;After spending years advocating for strong team dynamics in software engineering, I
have been fascinated as AI tools have entered our development workflows. In one of
my previous &lt;a href=&#34;https://jdriven.com/blog/2025/10/Team-dynamics-to-the-rescue&#34;&gt;blogs&lt;/a&gt;, I touched briefly on how AI might change team dynamics. Now, I
want to dive deeper into this transformation, as what we&amp;#8217;re experiencing isn&amp;#8217;t just a
new tool, it&amp;#8217;s a fundamental shift in how we work together.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The question isn&amp;#8217;t whether AI will impact team dynamics, it already has. The real
question is: how do we maintain the human connections that make teams truly
effective while embracing these new capabilities?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Spoiler alert: the answer isn&amp;#8217;t about the technology itself, it&amp;#8217;s about the choices we
make in how we use it. AI can be an extremely powerful tool, and I&amp;#8217;m a strong
supporter of its use. There are hidden dangers though. Using AI irresponsibly can
result in social isolation as I will explain in this blog, but we can avoid that by using
it consciously and intentionally.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;The isolation paradox&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Here&amp;#8217;s something I&amp;#8217;ve noticed: AI assistants are incredibly helpful, but they&amp;#8217;re also
incredibly solitary. When a developer gets stuck on a problem, they now have a
choice. Walk over to a colleague&amp;#8217;s desk (or ping them on Slack/Teams) and discuss
the issue, or ask an AI assistant for a solution.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The AI option is tempting. It&amp;#8217;s instant. It doesn&amp;#8217;t judge. It won&amp;#8217;t roll its eyes at what
might seem like a basic question. And it&amp;#8217;s always available, even at 2 AM when
you&amp;#8217;re debugging that critical production issue.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;But here&amp;#8217;s the paradox: every time we choose AI over human interaction, we lose
something valuable. We lose the spontaneous conversations that lead to unexpected
insights. We lose the knowledge sharing that happens naturally when explaining a
problem to someone else. We lose the social bonds that make teams resilient during
challenging times.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I&amp;#8217;ve seen developers who used to be highly collaborative become increasingly
isolated. They&amp;#8217;re productive, sure. Their code gets written. But they&amp;#8217;re operating in a
bubble, reinforced by an AI that reflects their own thinking patterns back at them.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;The echo chamber effect&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;When you collaborate with humans, you get challenged. Your assumptions get
questioned. Someone points out the edge case you missed or the security
vulnerability you overlooked. This friction, while sometimes uncomfortable, is what
makes software robust and developers evolve to the ‘next level’.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;AI assistants, for all their capabilities, tend to be agreeable. They generate solutions
based on patterns they&amp;#8217;ve learned, but they don&amp;#8217;t push back the way a senior
developer would. Junior developers do this too through casual feedback that forces
you to reconsider assumptions you didn&amp;#8217;t know you were making.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I&amp;#8217;ve reviewed code where developers clearly used AI assistance, and while the code
works, it often lacks the thoughtfulness that comes from human discussion. It solves
the immediate problem but misses the bigger picture. The architectural
considerations and more important the lessons learned from past mistakes.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;This creates an echo chamber where developers stay trapped in their own
perspective, with AI amplifying rather than challenging their approach.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock text-center&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/04/ConfirmationBias_web.png&#34; alt=&#34;ConfirmationBias web&#34; width=&#34;50%&#34;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Next in this series: how AI impacts learning, knowledge transfer, and the balance between speed and depth.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</content>
        <category term="Team Dynamics" scheme="https://jdriven.com/blog/category/Team-Dynamics/" />
        <category term="Tech Culture" scheme="https://jdriven.com/blog/category/Team-Dynamics/Tech-Culture/" />
        <category term="AI" scheme="https://jdriven.com/blog/tag/AI/" />
        <category term="Techradar" scheme="https://jdriven.com/blog/tag/Techradar/" />
    </entry>
    <entry>
        <id>https://jdriven.com/blog/2026/04/Nushell-Niceties-Check-Semantic-Version-Is-A-Match/</id>
        <title>Nushell Niceties: Check Semantic Version Is A Match</title>
        <social:hashtags>#Nushell</social:hashtags>
        <link rel="alternate" href="https://jdriven.com/blog/2026/04/Nushell-Niceties-Check-Semantic-Version-Is-A-Match/"/>
        <published>2026-04-28T04:58:11.000Z</published>
        <updated>2026-04-28T04:58:11.000Z</updated>
        <author>
            <name>mrhaki</name>
            <social:mastodon>mrhaki@mastodon.online</social:mastodon>
            <social:bluesky>mrhaki.com</social:bluesky>
            <uri>https://jdriven.com/blog/author/mrhaki</uri>
        </author>
        <summary type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In a &lt;a href=&#34;https://jdriven.com/blog/2026/04/Nushell-Niceties-Transform-Values-Into-Semver-Types/&#34;&gt;previous blogpost&lt;/a&gt; you can learn about the &lt;code&gt;semver&lt;/code&gt; command in Nushell to transform a string value into a semver type. The command has a subcommand &lt;code&gt;match-req&lt;/code&gt;. You can use this command to check if a version matches part of the semantic version parts. The result is a boolean value. The version to compare with doesn’t have to defined fully, but could exist of only the major, minor or patch parts. The value you pass can also be used to check if a version is greater or smaller than a given version. A range with a lower and upper version to match on can be defined as well. The boundary values are separated by a comma.&lt;/p&gt;
&lt;/div&gt;</summary>
        <content type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In a &lt;a href=&#34;https://jdriven.com/blog/2026/04/Nushell-Niceties-Transform-Values-Into-Semver-Types/&#34;&gt;previous blogpost&lt;/a&gt; you can learn about the &lt;code&gt;semver&lt;/code&gt; command in Nushell to transform a string value into a semver type. The command has a subcommand &lt;code&gt;match-req&lt;/code&gt;. You can use this command to check if a version matches part of the semantic version parts. The result is a boolean value. The version to compare with doesn’t have to defined fully, but could exist of only the major, minor or patch parts. The value you pass can also be used to check if a version is greater or smaller than a given version. A range with a lower and upper version to match on can be defined as well. The boundary values are separated by a comma.&lt;/p&gt;
&lt;/div&gt;
&lt;span id=&#34;more&#34;&gt;&lt;/span&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In the following example the command &lt;code&gt;semver match-req&lt;/code&gt; is used with different values:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-nu hljs&#34; data-lang=&#34;nu&#34;&gt;use std/assert

plugin use semver

let version = &#39;4.0.2&#39;

assert ($version | semver match-req &#39;4.0.2&#39;)
assert ($version | semver match-req &#39;4&#39;)
assert ($version | semver match-req &#39;4.0&#39;)

assert ($version | semver match-req &#39;&amp;gt;=4&#39;)
assert ($version | semver match-req &#39;&amp;gt;3&#39;)
assert ($version | semver match-req &#39;&amp;lt;5&#39;)
assert ($version | semver match-req &#39;&amp;gt;4.0.1&#39;)

assert ($version | semver match-req &#39;&amp;gt;3,&amp;lt;5&#39;)
assert ($version | semver match-req &#39;&amp;gt;=4.0,&amp;lt;4.1&#39;)

assert not ($version | semver match-req &#39;3&#39;)
assert not ($version | semver match-req &#39;&amp;gt;5&#39;)
assert not ($version | semver match-req &#39;&amp;lt;4&#39;)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Written with Nushell 0.111.0.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://blog.mrhaki.com/2026/04/nushell-niceties-check-semantic-version.html&#34;&gt;Original post&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;</content>
        <category term="Nushell" scheme="https://jdriven.com/blog/category/Nushell/" />
        <category term="Nushell" scheme="https://jdriven.com/blog/tag/Nushell/" />
    </entry>
    <entry>
        <id>https://jdriven.com/blog/2026/04/sizing-solutions/</id>
        <title>Considerations on cognitive load and organisational structure in sociotechnical systems.</title>
        <social:hashtags>#TeamTopologies #Cognitiveload #Sociotechnicalsystems #Domain-drivendesign #Agilescaling</social:hashtags>
        <link rel="alternate" href="https://jdriven.com/blog/2026/04/sizing-solutions/"/>
        <published>2026-04-23T07:00:00.000Z</published>
        <updated>2026-04-23T07:00:00.000Z</updated>
        <author>
            <name>Martijn Ras</name>
            <uri>https://jdriven.com/blog/author/martijn-ras</uri>
        </author>
        <summary type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In this article we present our rule of thumb for the sizing of solutions based on what an organisation can handle.
Our primary goal is to make you aware of cognitive load theory and sociological considerations on organisational structure.
Be aware that these are somewhat fuzzy theories, which are still debated and do not provide us with definitive answers.
We are still convinced that taking these ideas into consideration helps in making organisations more effective.
With our rule of thumb we hope to provide organisations a tool for conversation around how to effectively organize flows of work, without overloading and burning down teams.&lt;/p&gt;
&lt;/div&gt;</summary>
        <content type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In this article we present our rule of thumb for the sizing of solutions based on what an organisation can handle.
Our primary goal is to make you aware of cognitive load theory and sociological considerations on organisational structure.
Be aware that these are somewhat fuzzy theories, which are still debated and do not provide us with definitive answers.
We are still convinced that taking these ideas into consideration helps in making organisations more effective.
With our rule of thumb we hope to provide organisations a tool for conversation around how to effectively organize flows of work, without overloading and burning down teams.&lt;/p&gt;
&lt;/div&gt;
&lt;span id=&#34;more&#34;&gt;&lt;/span&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;We start with a short introduction of cognitive load theory and sociological considerations on organisational structure.
We finish by examining the organisational structures defined by various agile frameworks.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;This is the second iteration of this article. We have now defined the organisational construct in a more theoretical and framework/platform agnostic manner, where the &lt;a href=&#34;https://jdriven.com/blog/2024/03/sizing-solutions-around-cognitive-load-and-organizational-constructs&#34;&gt;first iteration&lt;/a&gt; was written around the three organizational constructs defined by SAFe &lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_1&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_1&#34; title=&#34;View footnote.&#34;&gt;1&lt;/a&gt;]&lt;/sup&gt;. We decided to dive into the various agile scaling frameworks/platforms that we are currently aware of an discover their approach to organisational constructs. We have added a table that summarizes this information. We have also added a section with the relevant sections from these frameworks/platforms.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Cognitive load theory&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The history of cognitive load theory can be traced to the beginning of cognitive science in the 1950s and the work of George Armitage Miller. His classic paper “The magical number seven, plus or minus two: some limits on our capacity for processing information” &lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_2&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_2&#34; title=&#34;View footnote.&#34;&gt;2&lt;/a&gt;]&lt;/sup&gt;, published in 1956, was perhaps the first to suggest our working memory capacity has inherent limits. His experimental results suggested that humans are generally able to hold only seven plus or minus two units of information in short-term memory.`&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cognition&lt;/strong&gt; is the mental action or process of acquiring knowledge and understanding through thought, experience, and the senses.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cognitive load&lt;/strong&gt; is the amount of mental effort caused by factors such domain complexity, technology needed, and related overhead.  There are broadly three types of cognitive load that are believed to circularly influence each other, according to work conducted in instructional design pedagogy:&lt;/p&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Intrinsic cognitive load&lt;/strong&gt; is the inherent level of difficulty associated with a specific instructional topic.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Extraneous cognitive load&lt;/strong&gt; is generated by the manner in which information is presented to learners and is under the control of instructional designers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Germane cognitive load&lt;/strong&gt; refers to the working memory resources that the learner dedicates to managing the intrinsic cognitive load associated with the essential information for learning.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cognitive capacity&lt;/strong&gt; is the maximum cognitive load an organisational construct can handle.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Organisational structure&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;We consider an organisation to be an entity comprising a group of persons having a particular purpose. To be effective every organisation will organise itself in one or more organisational constructs. We start by looking at sociology for considerations on the size and cohesion of groups.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Group size&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The number of people involved is an important characteristic of any grouping in which social behavior occurs. Large groupings have a tendency to divide into smaller subgroups.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;dlist&#34;&gt;
&lt;dl&gt;
&lt;dt class=&#34;hdlist1&#34;&gt;&lt;strong&gt;Dyad&lt;/strong&gt; &lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_3&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_3&#34; title=&#34;View footnote.&#34;&gt;3&lt;/a&gt;]&lt;/sup&gt;&lt;/dt&gt;
&lt;dd&gt;
&lt;p&gt;A group of two persons is important either as a stand-alone group or as a building block of larger groupings. Both persons are able to retain their individuality as there is no fear that another may shift the balance of the group.
&lt;em&gt;An infant requires a caregiver in order to survive, so life begins in a pair relationship that is apt to influence later ones.&lt;/em&gt;&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class=&#34;hdlist1&#34;&gt;&lt;strong&gt;Triad&lt;/strong&gt; &lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_4&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_4&#34; title=&#34;View footnote.&#34;&gt;4&lt;/a&gt;]&lt;/sup&gt;&lt;/dt&gt;
&lt;dd&gt;
&lt;p&gt;A group of three persons is hard to maintain. After all, it is easier to deal with one other person than with two. Besides, two of the people in a triad are apt to find it easier to relate to each other than to the other partner. That can motivate the neglected party to drop out of the group. In history, three leaders have sometimes attempted to share political power in a triumvirate, with little long-term success. On the other hand, groups of three can be very stable if there is a leader and two followers, such as a family of a single parent and two children.&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class=&#34;hdlist1&#34;&gt;&lt;strong&gt;Tetrad&lt;/strong&gt; &lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_5&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_5&#34; title=&#34;View footnote.&#34;&gt;5&lt;/a&gt;]&lt;/sup&gt;&lt;/dt&gt;
&lt;dd&gt;
&lt;p&gt;A group of four persons tends to not last very long, with the notable exception of vocal and musical quartets. Two persons in the group are apt to find it more satisfying to relate to each other than to either of the other persons. If the other two feel left out, they have at least that in common. They may feel a need to counteract the advantage a pair has when acting together over an individual operating alone. The relationship becomes one of two pairs rather than an effective group of four members.&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/div&gt;
&lt;div class=&#34;sect4&#34;&gt;
&lt;h5&gt;Cohesion&lt;/h5&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Herbert Arnold Thelen, in his 1949 paper “Group Dynamics in Instruction: Principle of Least Group Size” &lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_6&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_6&#34; title=&#34;View footnote.&#34;&gt;6&lt;/a&gt;]&lt;/sup&gt;, proposed a principle that for members of groups to have maximum motivation to perform, the number of members in each should be the smallest &#34;in which it is possible to have represented at a functional level all the social and achievement skills required for the particular required activity.
Robert Melancton Metcalfe, in his 1983 presentation to the 3Com sales force &lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_7&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_7&#34; title=&#34;View footnote.&#34;&gt;7&lt;/a&gt;]&lt;/sup&gt;, states that the financial value or influence of a telecommunications network is proportional to the square of the number of connected users of the system:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/04/connections.png&#34; alt=&#34;metcalfe&amp;#8217;s law&#34;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;As a group gets larger, adding another person has less effect on its characteristics. The communication overhead within a group increases as the number of persons in a group increases. It also takes some time for the person added to a group to become productive. The complexity of a team’s interactions grows as the team expands, making it crucial to understand the stages of team development, the impact of multiculturalism, and the role of communication styles. &lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_8&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_8&#34; title=&#34;View footnote.&#34;&gt;8&lt;/a&gt;]&lt;/sup&gt; &lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_9&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_9&#34; title=&#34;View footnote.&#34;&gt;9&lt;/a&gt;]&lt;/sup&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;A consideration at least in smaller groups, though, is whether the number of members is even or odd. Doing things together is easy if all those involved agree on what to do, or if the majority opinion is able to override objections without repelling the objectors. A group of six or eight members can split into two equal factions, so decision-making is not apt to be as easy as if the size were five, seven or nine. As groups get larger stalemates are less likely but still can be troublesome. If a group makes decisions by voting it can adopt a means of tie-breaking (requiring one vote more than 50% for a measure to be adopted, giving the presiding officer a tie-breaking vote, or deciding by coin toss). Even-sized small groups often experience lower cohesion than odd-sized small groups.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Robin Ian MacDonald Dunbar, in his 1992 paper “Neocortex size as a constraint on group size in primates” &lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_10&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_10&#34; title=&#34;View footnote.&#34;&gt;10&lt;/a&gt;]&lt;/sup&gt;, defined the following ‘magic numbers’ of group sizes:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;5: Our best friends and closest support group&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;15: The close friends we trust&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;50: Persons we call friends or would invite to a group dinner&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;150: Our stable relationships&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;500: The number of not-so-close acquaintances we can keep&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;1500: The number of persons we can name and recognize&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Frederick Phillips Brooks, in his 1975 book “The Mythical Man-Month” &lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_11&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_11&#34; title=&#34;View footnote.&#34;&gt;11&lt;/a&gt;]&lt;/sup&gt;, observed that under certain conditions, an incremental person when added to a project makes it take more, not less time. Adding more persons to a highly divisible task, such as cleaning rooms in a hotel, decreases the overall task duration (up to the point where additional workers get in each other&amp;#8217;s way). However, other tasks including many specialties in software projects are less divisible; Brooks points out this limited divisibility with another example: while it takes one woman nine months to make one baby, &#34;nine women can&amp;#8217;t make a baby in one month&#34;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Rule of thumb for sizing of solutions&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;As collaboration is expensive in terms of cognitive load, this puts a constraint on the size of every organisational construct. Every solution, and every autonomous part thereof, adds an amount of cognitive load to the organisational construct responsible for creating/changing/operating/running that solution, or autonomous part thereof.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Architects are expected to intentionally decompose solutions into autonomous parts. “Domain-Driven Design” &lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_12&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_12&#34; title=&#34;View footnote.&#34;&gt;12&lt;/a&gt;]&lt;/sup&gt; defines these as bounded contexts, which are isolated from each other and which are easier to change, test, and incrementally develop. This separation allows teams to autonomously focus on their specific bounded contexts without undue interference or complexity from other bounded contexts, which will produce solutions that can be independently designed and delivered. Team Topologies &lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_13&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_13&#34; title=&#34;View footnote.&#34;&gt;13&lt;/a&gt;]&lt;/sup&gt; offers an approach to designing team-of-teams organizations for fast flow of value. Team Topologies identifies 4 fundamental topologies and three core interaction modes, which explicitly guide inter-team interaction and help create well defined boundaries that reduce cognitive load for each team.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;While there is a one-on-one-relation between an autonomous part and a team and a solution and a team-of-teams, be aware that the other way around a team can own multiple autonomous parts and a team-of-teams can own multiple solutions!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Whichever problem an organisation is solving, the solution should be questioned on how well its ‘cognitive load’ fits within the ‘cognitive capacity’ of the organisational constructs.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;We have a rule of thumb for the sizing of solutions:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The ‘cognitive load’ of every autonomous part of a solution must not exceed the ‘cognitive capacity’ of a team.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The ‘cognitive load’ of a solution must not exceed the ‘cognitive capacity’ of a team-of-teams.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The ‘cognitive load’ of a large-scale solution must not exceed the ‘cognitive capacity’ of multiple team-of-teams.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&#34;Less is more&#34;: Keep organisational constructs small and remember that in complex problem spaces, employing multiple smaller solutions reduces the overall cognitive load.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;We hope this article starts a two way conversation within your organisation to prevent ‘cognitive overload’.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;olist arabic&#34;&gt;
&lt;div class=&#34;title&#34;&gt;Key takeaways:&lt;/div&gt;
&lt;ol class=&#34;arabic&#34;&gt;
&lt;li&gt;
&lt;p&gt;Collaboration is an expensive type of interaction that limits the size of a team.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use “Team Topologies” to design organisational constructs (teams and teams-of-teams) which promote flow and focus and align communication structure and architecture.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use “Domain-Driven Design” to decompose solutions into clever bounded contexts:&lt;/p&gt;
&lt;div class=&#34;olist loweralpha&#34;&gt;
&lt;ol class=&#34;loweralpha&#34; type=&#34;a&#34;&gt;
&lt;li&gt;
&lt;p&gt;That match the organisational constructs&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;That reduce the overall cognitive load by minimising the size and complexity of the solution&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;Organisational structures as defined by various agile frameworks&lt;/h3&gt;
&lt;table class=&#34;tableblock frame-all grid-all stretch&#34;&gt;
&lt;colgroup&gt;
&lt;col style=&#34;width: 16.6666%;&#34;&gt;
&lt;col style=&#34;width: 16.6666%;&#34;&gt;
&lt;col style=&#34;width: 16.6666%;&#34;&gt;
&lt;col style=&#34;width: 16.6666%;&#34;&gt;
&lt;col style=&#34;width: 16.6666%;&#34;&gt;
&lt;col style=&#34;width: 16.667%;&#34;&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34; rowspan=&#34;3&#34;&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;Deliverable&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;autonomous part of a solution&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;solution&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;large-scale solution&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;Multiple  Solutions&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;cognitive load&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;&amp;#8656;&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;&amp;#8656;&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;&amp;#8656;&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;&amp;gt;&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;Organisational construct&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;one team&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;one team-of-teams&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;mulitple team-of-teams&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;N.A.&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34; rowspan=&#34;7&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;Agile Scaling Framework&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;Scrum&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;Scrum Team&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&#34;tableblock&#34;&gt;(&amp;lt;10 persons)&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;N.A.&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;N.A.&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;N.A.&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;Scrum-of-scrums&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;Development Team&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;Scrum Team&lt;/p&gt;
&lt;p class=&#34;tableblock&#34;&gt;(&amp;lt;10 persons)&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;N.A.&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;N.A.&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;Metascrum&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;Scrum Team&lt;/p&gt;
&lt;p class=&#34;tableblock&#34;&gt;(&amp;lt;10 persons)&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;MetaScrum&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;N.A.&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;N.A.&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;SAFe&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;Agile Team&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&#34;tableblock&#34;&gt;(&amp;lt;10 persons)&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;[Essential]&lt;/p&gt;
&lt;p class=&#34;tableblock&#34;&gt;Agile Release Train&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&#34;tableblock&#34;&gt;(50-125 persons / 5-15 Agile Teams)&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;[Large Solution/Portfolio)&lt;/p&gt;
&lt;p class=&#34;tableblock&#34;&gt;Solution Train&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&#34;tableblock&#34;&gt;(2+ Agile Release Trains)&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;[Full Configuration]&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&#34;tableblock&#34;&gt;(2+ Solution Trains)&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;Less&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;Scrum Team&lt;/p&gt;
&lt;p class=&#34;tableblock&#34;&gt;(&amp;lt;10 persons)&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;Less&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&#34;tableblock&#34;&gt;(2-8 Scrum Teams)&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;Less Huge&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&#34;tableblock&#34;&gt;(8+ Scrum Teams)&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;N.A.&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;Disciplined Agile Delivery&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;Small Agile Team&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&#34;tableblock&#34;&gt;(2-15 persons)&lt;/p&gt;
&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;Medium Sized Team&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&#34;tableblock&#34;&gt;(25-30 persons)&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;Program&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;Medium-Sized&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&#34;tableblock&#34;&gt;(12-50 persons)&lt;/p&gt;
&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;Large-Sized&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&#34;tableblock&#34;&gt;(35+ persons)&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;N.A.&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;N.A.&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;Nexus&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;Scrum Team&lt;/p&gt;
&lt;p class=&#34;tableblock&#34;&gt;(&amp;lt;10 persons)&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;Nexus&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&#34;tableblock&#34;&gt;3-9 Scrum Teams&lt;/p&gt;
&lt;p class=&#34;tableblock&#34;&gt;+&lt;/p&gt;
&lt;p class=&#34;tableblock&#34;&gt;&lt;strong&gt;Nexus Integration Team&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;N.A.&lt;/p&gt;&lt;/td&gt;
&lt;td class=&#34;tableblock halign-left valign-top&#34;&gt;&lt;p class=&#34;tableblock&#34;&gt;N.A.&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;Background info on the various agile frameworks&lt;/h3&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Scrum &lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_14&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_14&#34; title=&#34;View footnote.&#34;&gt;14&lt;/a&gt;]&lt;/sup&gt;&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The fundamental unit of Scrum is a small team of people, a &lt;strong&gt;Scrum Team&lt;/strong&gt;. The Scrum Team consists of one Scrum Master, one Product Owner, and Developers. Within a Scrum Team, there are no sub-teams or hierarchies. It is a cohesive unit of professionals focused on one objective at a time, the Product Goal.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Scrum Teams are cross-functional, meaning the members have all the skills necessary to create value each Sprint. They are also self-managing, meaning they internally decide who does what, when, and how.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The Scrum Team is small enough to remain nimble and large enough to complete significant work within a Sprint, typically 10 or fewer people. In general, we have found that smaller teams communicate better and are more productive. If Scrum Teams become too large, they should consider reorganizing into multiple cohesive Scrum Teams, each focused on the same product. Therefore, they should share the same Product Goal, Product Backlog, and Product Owner.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The Scrum Team is responsible for all product-related activities from stakeholder collaboration, verification, maintenance, operation, experimentation, research and development, and anything else that might be required. They are structured and empowered by the organization to manage their own work. Working in Sprints at a sustainable pace improves the Scrum Team’s focus and consistency.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The entire Scrum Team is accountable for creating a valuable, useful Increment every Sprint. Scrum defines three specific accountabilities within the Scrum Team: the Developers, the Product Owner, and the Scrum Master.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Scrum Team &amp;#8656; 10 persons:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Team members&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Scrum Master&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;1 Product Owner&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;1 Product (Goal)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;1 Product Backlog&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;1 Sprint (across all Teams)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;1 (Potentially Shippable) Product Increment&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Scrum of Scrums &lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_15&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_15&#34; title=&#34;View footnote.&#34;&gt;15&lt;/a&gt;]&lt;/sup&gt;&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;When a Scrum Team works on a single product with multiple &lt;strong&gt;Development Teams&lt;/strong&gt;, unresolved dependencies within individual Development Teams create a shared challenge of the Scrum Team.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The &lt;strong&gt;Scrum of Scrums&lt;/strong&gt; is a meeting to coordinate these unresolved dependencies and shared work, in which an ambassador from every Development Team participates.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Metascrum &lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_16&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_16&#34; title=&#34;View footnote.&#34;&gt;16&lt;/a&gt;]&lt;/sup&gt;&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The &lt;strong&gt;Metascrum&lt;/strong&gt; is a forum where the entire enterprise can align behind the Product Owners’ backlogs at every level of Scrum in the organization:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;1 MetaScrum Product Owner&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Multiple Product Owners&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Management&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Other Stakeholders&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;SAFe &lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_17&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_17&#34; title=&#34;View footnote.&#34;&gt;17&lt;/a&gt;]&lt;/sup&gt;&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;SAFe integrates the power of Lean, Agile, and DevOps into a comprehensive operating system that helps enterprises thrive in the digital age by delivering innovative products and services faster, more predictably, and with higher quality.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;Agile Team&lt;/strong&gt; = &amp;lt; 10 persons&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;Agile Release Train (ART)&lt;/strong&gt; = 50-125 persons/5-15 teams&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;A team of Agile Teams that align to a shared business and technology mission. Each is a virtual organization (typically 50 – 125 persons) that plans, commits, develops, and deploys together. ARTs are organized around the enterprise’s significant Development Value Streams and exist solely to realize the promise of that value by building and delivering Solutions that benefit the Customer. In addition to the Agile teams, the following roles aid the successful execution of the ART:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Release Train Engineer (RTE) is a servant leader who facilitates ART execution, impediment removal, risk and dependency management, and continuous improvement.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Product Management is largely responsible for ‘what gets built,’ as defined by the Vision, Roadmap, and new Features in the ART Backlog. They work with customers, teams, and Product Owners to understand and communicate their needs and participate in solution validation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;System Architect is an individual or team that defines the system’s overall architecture. They work at a level of abstraction above the teams and components and typically define Nonfunctional Requirements (NFRs), major system elements, subsystems, and interfaces.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Business Owners are key stakeholders of the ART, with final responsibility for the business outcomes of the train.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Customers are the ultimate economic buyers or value users of the solution.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In addition to these critical ART roles, the following functions play an essential part in ART success:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;System Teams typically assist in building and maintaining development, continuous integration, and test environments.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Shared Services are specialists necessary for the success of an ART but cannot be dedicated to a specific train. They often include data security, information architects, site reliability engineering (SRE), database administrators (DBAs), and many more.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;Solution Train&lt;/strong&gt; = 2+ Agile Release Trains&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The organizational construct used to build large solutions that requires the coordination of multiple ARTs and suppliers. In addition to the ARTs and Agile teams, the following roles aid the Solution Train’s successful execution:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Solution Management defines and supports building desirable, feasible, viable, and sustainable large-scale business solutions that meet customer needs over the solution’s significant lifespan. They represent the customer and business needs to the ARTs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Solution Architects define and communicate a shared technical and architectural vision across the Solution Train to help ensure the solution under development is fit for its intended purpose. They work with the ART’s System Architects to help guide their portion of the solution’s design.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Solution Train Engineer (STE) is the coach for the Solution Train, facilitating and guiding the work of all ARTs and suppliers. The STE works with Release Train Engineers (RTEs) to facilitate ART execution and coordinate delivery.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Suppliers are internal or external organizations that develop and deliver components, subsystems, or services, which help Solution Trains deliver solutions to customers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Business Owners are key stakeholders of the Solution Train, with final responsibility for the business outcomes. They, along with Solution Train leaders, may also serve as business owners for the Solution Train’s ARTs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Customers are the buyers of the solution and ultimately determine value. When delivering in a supply chain, customers work closely with Solution Management and other key stakeholders to define and adjust the solution’s vision, intent, and delivery roadmap.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Due to their size and cost, large solution development attracts a lot of attention, heightening stakeholder involvement and increasing opinions, governance, and oversight. The Solution Train leadership team – Solution Managers, Architects, and STE – must be aligned and represent a consistent force to realize the solution’s vision. The STE should ensure this team has the time and space to form as a team and build cross-role transparency and trust. The following roles also play an essential part in the Solution Train’s success:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A System Team is typically formed for the Solution Train to address the integration issues across the ARTs. Individual ARTs may have their own Systems Teams. All System Teams share resources and align on common infrastructure and toolchains where possible.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Shared Services represent the specialty roles, persons, and services required for the success of the Solution Train, but that cannot be dedicated full-time. Sometimes, they may be devoted to the Solution Train and shared across the ARTs.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;SAFe defines a number of configurations, which to adopt depends on your organization’s size, complexity, and need for strategic alignment:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;Essential&lt;/strong&gt; = 1 Agile Release Train = 50-125 persons/5-15 teams&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;Large Solution&lt;/strong&gt; = 1 Solution Train = 2+ Agile Release Trains&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Large Solution SAFe is for enterprises building large and complex solutions that do not require portfolio concerns.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;Portfolio&lt;/strong&gt; = 2+ Agile Release Trains&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;Full&lt;/strong&gt; = 2+ Solution Trains&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;A SAFe Portfolio is a set of value streams that delivers a continuous flow of valuable solutions to customers within a common funding and governance model. The SAFe Portfolio consists of multiple Development Value Streams (DVS). Each DVS has a lean budget and consists of one or more Solutions and the persons who maintain and evolve those solutions. Typically, these persons are organized into Agile Teams, Agile Release Trains (ARTs), and Solution Trains. Additionally, the portfolio defines a set of Portfolio Epics representing significant solution development initiatives. The Portfolio Backlog captures those epics to enable governance of their investments’ discovery, risk, and MVP evidence. Portfolio epics may span multiple DVSs and require coordination using Value Stream Coordination practices.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Epic Owners take responsibility for guiding the collaborations needed to realize value from epics.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enterprise Architects assist in ensuring Business Epics advance the overall enterprise technical architecture. For more technical Enabler Epics, they may also act as Epic Owners.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The Value Management Office (VMO) coordinates, supports, and encourages continuous improvement across the portfolio. To ensure the maximum flow of business value through each DVS, portfolio members apply Value Stream Management. The portfolio may also coordinate and apply Big Data practices to ensure optimal use, and that value is gained from the data collected and managed across the DVS.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;LeSS &lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_18&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_18&#34; title=&#34;View footnote.&#34;&gt;18&lt;/a&gt;]&lt;/sup&gt;&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;LeSS is Scrum applied to many teams working together on one product.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;Scrum Team&lt;/strong&gt; = 3-9 persons&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;LeSS&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;2-8 Scrum Teams&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;Less Huge&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;8+ Scrum Teams&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Multiple Requirement Areas&lt;/p&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;1 Area Product Owner&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;1 Area Product Backlog [Filter/view on Product Backlog]&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;4-8 Teams&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Disciplined Agile Delivery &lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_19&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_19&#34; title=&#34;View footnote.&#34;&gt;19&lt;/a&gt;]&lt;/sup&gt;&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;Scrum Team&lt;/strong&gt; = 2+ persons&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;Program&lt;/strong&gt; = Team of Scrum Teams&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Scrum Teams can range in size from two persons to twenty to two hundred or more. Larger teams are typically formed to address more complex problems, and as a result large teams take on the challenges of greater domain complexity and/or greater technical complexity as described below. Team size tends to directly affect how you organize the team and how you coordinate within the team. For example, a large agile team of 600 will be organized into subteams and a leadership team will be required for coordination, something we capture in DA&amp;#8217;s Program life cycle. A team of 50 will also be organized into subteams, although coordination will likely be simpler and possibly handled by a daily coordination meeting of representatives from each subteam (a technique referred tas a Scrum of Scrums). It is fairly straightforward to coordinate the activities of a team of 10 persons.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;A program is a collection of related initiatives managed in a coordinated way to obtain benefits not available from managing them individually. A program team is typically organized as a team of teams, called sub-teams or squads. Structures are required to coordinate persons, requirements, and technical concerns within the overall program. Where a simple “scrum of scrums” may suffice coordination on small-to-medium sized programs (say up to five or six sub-teams) small-to-medium sized programs (say up to five or six sub-teams).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Small Agile Teams&lt;/strong&gt; = 2-15 persons&lt;/p&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Small DAD Team:&lt;/p&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Team Members&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Product Owner&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Team Lead (an evolution of Scrum’s Scrum Master role) and the Architecture Owner are often, but not always, the same person on small teams. &lt;br&gt;
This can be challenging because good Team Leads need solid persons and leadership skills whereas good Architecture Owners need solid technical skills and knowledge of the existing infrastructure and it can be hard to find all of these in a single person.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Supporting Cast:&lt;/p&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Technical Expert(s)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Domain Expert(s)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Independent Tester(s)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Integrator(s)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Medium Sized Teams&lt;/strong&gt; = 25-30 persons&lt;/p&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;DAD Team:&lt;/p&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Team Members&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Product Owner&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Team Lead&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Architecture Owner&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Specialist(s)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Supporting Cast:&lt;/p&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Technical Expert(s)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Domain Expert(s)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Independent Tester(s)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Medium-Sized Team-of-Teams/Programs&lt;/strong&gt; = 12-50 persons&lt;/p&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;DAD Subteam(s):&lt;/p&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Team Members&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Product Owner&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Team Lead&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Architecture Owner&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Specialist(s)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Supporting Cast:&lt;/p&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Technical Expert(s)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Domain Expert(s)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Independent Tester(s)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Integrator(s)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Large-Sized Team-of-Teams/Programs&lt;/strong&gt; = 35+ persons&lt;/p&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Leadership Team:&lt;/p&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A Product Management (or Product Ownership) strategy where the Product Owners coordinate their activities&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;An Architecture (or Architecture Ownership) strategy where the Architecture Owners coordinate their activities&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A Product Coordination (or Management) strategy where the Team Leads coordinate their activities.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;An optional Program Manager/Coordinator, a specialist role, is responsible for coordinating the overall leadership team.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DAD Subteam(s):&lt;/p&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Team Members&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Product Owner&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Team Lead&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Architecture Owner&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Specialist(s)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Supporting Cast:&lt;/p&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Technical Expert(s)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Domain Expert(s)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Independent Tester(s)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Integrator(s)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Nexus &lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_20&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_20&#34; title=&#34;View footnote.&#34;&gt;20&lt;/a&gt;]&lt;/sup&gt;&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;Nexus&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;3-9 Scrum Teams&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Nexus Integration Team&lt;/p&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;1 Product Owner&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;1 Scrum Master&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Appropriate members from the Scrum Teams (with the necessary skills and knowledge to help resolve the issues the Nexus faces at any point in time)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The Nexus Integration Team is accountable for ensuring that a done Integrated Increment (the combined work completed by a Nexus) is produced at least once a Sprint. It provides the focus that makes possible the accountability of multiple Scrum Teams to come together to create valuable, useful Increments, as prescribed in Scrum. Membership in the Nexus Integration Team takes precedence over individual Scrum Team membership. As long as their Nexus Integration Team responsibility is satisfied, they can work as team members of their respective Scrum Teams. This preference helps ensure that the work to resolve issues affecting multiple teams has priority.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Scrum@Scale &lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_21&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_21&#34; title=&#34;View footnote.&#34;&gt;21&lt;/a&gt;]&lt;/sup&gt;&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Scrum Team = &amp;lt; 10 persons&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scrum of Scrums (SoS)&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;4-5 Scrum Teams&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Product Owner Team&lt;/p&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Scrum of Scrums Master&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Chief Product Owner&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Metascrum&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scrum of Scrum of Scrums (SoSoS)&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Multiple Scrum of Scrums&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Executive Action Team&lt;/p&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Scrum of Scrum of Scrums Master&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Product Owner&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Executive Metascrum&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Crystal &lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_22&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_22&#34; title=&#34;View footnote.&#34;&gt;22&lt;/a&gt;]&lt;/sup&gt;&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Various methodologies in the Crystal family also known as weights of the Crystal approach are represented by different colors of the spectrum:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Crystal Clear = 1-6 persons&lt;/strong&gt; &lt;br&gt;
Suitable for short-term projects where members work out in a single workspace.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Crystal Yellow = 7-20 persons&lt;/strong&gt; &lt;br&gt;
Feedback is taken from Real Users. This variant involves automated testing which resolves bugs faster and reduces the use of too much documentation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Crystal Orange = 21-40 persons&lt;/strong&gt; &lt;br&gt;
The team is split according to their functional skills. Here the project generally lasts for 1-2 years and the release is required every 3 to 4 months.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Crystal Orange Web = 21-40 persons&lt;/strong&gt; &lt;br&gt;
Projects that have a continually evolving code base that is being used by the public. It is also similar to Crystal Orange but here they do not deal with a single project but a series of initiatives that require programming.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Crystal Red = 40-80 persons&lt;/strong&gt; &lt;br&gt;
Teams can be formed and divided according to requirements.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Crystal Maroon = 80-200 persons&lt;/strong&gt; &lt;br&gt;
Large-sized projects where methods are different and as per the requirement of the software.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Crystal Diamond &amp;amp; Sapphire&lt;/strong&gt; &lt;br&gt;
This variant is used in large projects where there is a potential risk to human life.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Spotify Model &lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_23&#34; class=&#34;footnote&#34; href=&#34;#_footnotedef_23&#34; title=&#34;View footnote.&#34;&gt;23&lt;/a&gt;]&lt;/sup&gt;&lt;/h4&gt;
&lt;div class=&#34;dlist&#34;&gt;
&lt;dl&gt;
&lt;dt class=&#34;hdlist1&#34;&gt;&lt;strong&gt;Squads&lt;/strong&gt; (typically 6-12 persons)&lt;/dt&gt;
&lt;dd&gt;
&lt;p&gt;A Squad is similar to a Scrum team, and is designed to feel like a mini startup. They sit together, and they have all the skills and tools needed to design, develop, test, and release to production. They are a self organizing team and decide their own way of working – some use Scrum sprints, some use Kanban, some use a mix of these approaches. Each squad has a long term mission such as building and improving the Android client, creating the Spotify radio experience, scaling the backend systems, or providing payment solutions. A squad doesn’t have a formally appointed squad leader, but it does have a product owner.&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class=&#34;hdlist1&#34;&gt;&lt;strong&gt;Tribes&lt;/strong&gt; &amp;#8656; 100 persons&lt;/dt&gt;
&lt;dd&gt;
&lt;p&gt;A tribe is a collection of squads that work in related areas – such as the music player, or backend infrastructure. The tribe can be seen as the “incubator” for the squad mini startups. , and have a fair degree of freedom and autonomy. Each tribe has a tribe lead who is responsible for providing the best possible habitat for the squads within that tribe. The squads in a tribe are all physically in the same office, normally right next to each othereach other, and the lounge areas nearby promote collaboration between the squads. Tribes are sized based on the concept of the “Dunbar number”, which says that most persons cannot maintain a social relationship with more than 100 persons or so (the number is actually larger for groups that
are under intense survival pressure, which isn’t really the case at Spotify, believe it or not&amp;#8230;&amp;#8203;). When groups get too big, we start seeing more things like restrictive rules, bureaucracy, politics, extra layers of management, and other waste.
So tribes are designed to be smaller than 100 persons or so.&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class=&#34;hdlist1&#34;&gt;Chapters and Guilds&lt;/dt&gt;
&lt;dd&gt;
&lt;p&gt;This is the glue that keeps the company together, it gives us some economies of scale without sacrificing too much autonomy.&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class=&#34;hdlist1&#34;&gt;Chapter&lt;/dt&gt;
&lt;dd&gt;
&lt;p&gt;The chapter is your small family of persons having similar skills and working within the same general competency area, within the same tribe.&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class=&#34;hdlist1&#34;&gt;Guild&lt;/dt&gt;
&lt;dd&gt;
&lt;p&gt;A Guild is a more organic and wide reaching “community of interest”, a group of persons that want to share knowledge, tools, code, and practices. Chapters are always local to a Tribe, while a guild usually cuts across the whole organization. Some examples are: the web technology guild, the tester guild, the agile coach guild, etc.&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;footnotes&#34;&gt;
&lt;hr&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_1&#34;&gt;
&lt;a href=&#34;#_footnoteref_1&#34;&gt;1&lt;/a&gt;. &lt;a href=&#34;https://scaledagileframework.com&#34; class=&#34;bare&#34;&gt;https://scaledagileframework.com&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_2&#34;&gt;
&lt;a href=&#34;#_footnoteref_2&#34;&gt;2&lt;/a&gt;. &lt;a href=&#34;https://archive.org/details/miller1956_202204&#34; class=&#34;bare&#34;&gt;https://archive.org/details/miller1956_202204&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_3&#34;&gt;
&lt;a href=&#34;#_footnoteref_3&#34;&gt;3&lt;/a&gt;. &lt;a href=&#34;https://en.wikipedia.org/wiki/Dyad_(sociology&#34; class=&#34;bare&#34;&gt;https://en.wikipedia.org/wiki/Dyad_(sociology&lt;/a&gt;)
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_4&#34;&gt;
&lt;a href=&#34;#_footnoteref_4&#34;&gt;4&lt;/a&gt;. &lt;a href=&#34;https://en.wikipedia.org/wiki/Triad_(sociology&#34; class=&#34;bare&#34;&gt;https://en.wikipedia.org/wiki/Triad_(sociology&lt;/a&gt;)
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_5&#34;&gt;
&lt;a href=&#34;#_footnoteref_5&#34;&gt;5&lt;/a&gt;. &lt;a href=&#34;https://en.wikipedia.org/wiki/Size_of_groups,_organizations,_and_communities&#34; class=&#34;bare&#34;&gt;https://en.wikipedia.org/wiki/Size_of_groups,_organizations,_and_communities&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_6&#34;&gt;
&lt;a href=&#34;#_footnoteref_6&#34;&gt;6&lt;/a&gt;. &lt;a href=&#34;https://www.jstor.org/stable/1082755&#34; class=&#34;bare&#34;&gt;https://www.jstor.org/stable/1082755&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_7&#34;&gt;
&lt;a href=&#34;#_footnoteref_7&#34;&gt;7&lt;/a&gt;. &lt;a href=&#34;https://en.wikipedia.org/wiki/Metcalfe%27s_law&#34; class=&#34;bare&#34;&gt;https://en.wikipedia.org/wiki/Metcalfe%27s_law&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_8&#34;&gt;
&lt;a href=&#34;#_footnoteref_8&#34;&gt;8&lt;/a&gt;. &lt;a href=&#34;https://medium.com/@carlosbueno.kinder/the-complex-dynamics-of-team-growth-unraveling-the-layers-with-metcalfes-law-and-multicultural-efd29edf79c&#34; class=&#34;bare&#34;&gt;https://medium.com/@carlosbueno.kinder/the-complex-dynamics-of-team-growth-unraveling-the-layers-with-metcalfes-law-and-multicultural-efd29edf79c&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_9&#34;&gt;
&lt;a href=&#34;#_footnoteref_9&#34;&gt;9&lt;/a&gt;. &lt;a href=&#34;https://getlighthouse.com/blog/developing-leaders-team-grows-big&#34; class=&#34;bare&#34;&gt;https://getlighthouse.com/blog/developing-leaders-team-grows-big&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_10&#34;&gt;
&lt;a href=&#34;#_footnoteref_10&#34;&gt;10&lt;/a&gt;. &lt;a href=&#34;https://vidauniversoydemas.wordpress.com/wp-content/uploads/2013/06/sns3.pdf&#34; class=&#34;bare&#34;&gt;https://vidauniversoydemas.wordpress.com/wp-content/uploads/2013/06/sns3.pdf&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_11&#34;&gt;
&lt;a href=&#34;#_footnoteref_11&#34;&gt;11&lt;/a&gt;. &lt;a href=&#34;https://archive.org/details/mythicalmanmonth00broo/page/n5/mode/2up&#34; class=&#34;bare&#34;&gt;https://archive.org/details/mythicalmanmonth00broo/page/n5/mode/2up&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_12&#34;&gt;
&lt;a href=&#34;#_footnoteref_12&#34;&gt;12&lt;/a&gt;. &lt;a href=&#34;https://www.domainlanguage.com&#34; class=&#34;bare&#34;&gt;https://www.domainlanguage.com&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_13&#34;&gt;
&lt;a href=&#34;#_footnoteref_13&#34;&gt;13&lt;/a&gt;. &lt;a href=&#34;https://teamtopologies.com&#34; class=&#34;bare&#34;&gt;https://teamtopologies.com&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_14&#34;&gt;
&lt;a href=&#34;#_footnoteref_14&#34;&gt;14&lt;/a&gt;. &lt;a href=&#34;https://www.scrum.org&#34; class=&#34;bare&#34;&gt;https://www.scrum.org&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_15&#34;&gt;
&lt;a href=&#34;#_footnoteref_15&#34;&gt;15&lt;/a&gt;. &lt;a href=&#34;https://scrumbook.org.datasenter.no/product-organization-pattern-language/scrum-of-scrums.html&#34; class=&#34;bare&#34;&gt;https://scrumbook.org.datasenter.no/product-organization-pattern-language/scrum-of-scrums.html&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_16&#34;&gt;
&lt;a href=&#34;#_footnoteref_16&#34;&gt;16&lt;/a&gt;. &lt;a href=&#34;https://scrumbook.org.datasenter.no/product-organization-pattern-language/metascrum.html&#34; class=&#34;bare&#34;&gt;https://scrumbook.org.datasenter.no/product-organization-pattern-language/metascrum.html&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_17&#34;&gt;
&lt;a href=&#34;#_footnoteref_17&#34;&gt;17&lt;/a&gt;. &lt;a href=&#34;https://scaledagileframework.com&#34; class=&#34;bare&#34;&gt;https://scaledagileframework.com&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_18&#34;&gt;
&lt;a href=&#34;#_footnoteref_18&#34;&gt;18&lt;/a&gt;. &lt;a href=&#34;https://less.works&#34; class=&#34;bare&#34;&gt;https://less.works&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_19&#34;&gt;
&lt;a href=&#34;#_footnoteref_19&#34;&gt;19&lt;/a&gt;. &lt;a href=&#34;https://www.pmi.org/disciplined-agile&#34; class=&#34;bare&#34;&gt;https://www.pmi.org/disciplined-agile&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_20&#34;&gt;
&lt;a href=&#34;#_footnoteref_20&#34;&gt;20&lt;/a&gt;. &lt;a href=&#34;https://www.scrum.org/resources/nexus-guide&#34; class=&#34;bare&#34;&gt;https://www.scrum.org/resources/nexus-guide&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_21&#34;&gt;
&lt;a href=&#34;#_footnoteref_21&#34;&gt;21&lt;/a&gt;. &lt;a href=&#34;https://www.scrumatscale.com&#34; class=&#34;bare&#34;&gt;https://www.scrumatscale.com&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_22&#34;&gt;
&lt;a href=&#34;#_footnoteref_22&#34;&gt;22&lt;/a&gt;. &lt;a href=&#34;https://www.geeksforgeeks.org/crystal-methods-in-agile-development-framework&#34; class=&#34;bare&#34;&gt;https://www.geeksforgeeks.org/crystal-methods-in-agile-development-framework&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnotedef_23&#34;&gt;
&lt;a href=&#34;#_footnoteref_23&#34;&gt;23&lt;/a&gt;. &lt;a href=&#34;https://blog.crisp.se/wp-content/uploads/2012/11/SpotifyScaling.pdf&#34; class=&#34;bare&#34;&gt;https://blog.crisp.se/wp-content/uploads/2012/11/SpotifyScaling.pdf&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;</content>
        <category term="Cognitive load" scheme="https://jdriven.com/blog/category/Cognitive-load/" />
        <category term="Sociotechnical systems" scheme="https://jdriven.com/blog/category/Cognitive-load/Sociotechnical-systems/" />
        <category term="Team Topologies" scheme="https://jdriven.com/blog/tag/Team-Topologies/" />
        <category term="Cognitive load" scheme="https://jdriven.com/blog/tag/Cognitive-load/" />
        <category term="Sociotechnical systems" scheme="https://jdriven.com/blog/tag/Sociotechnical-systems/" />
        <category term="Domain-driven design" scheme="https://jdriven.com/blog/tag/Domain-driven-design/" />
        <category term="Agile scaling" scheme="https://jdriven.com/blog/tag/Agile-scaling/" />
    </entry>
    <entry>
        <id>https://jdriven.com/blog/2026/04/Conflux-Fullstackathon-2026/</id>
        <title>Building a fullstack digital city in kubernetes hosted on an EU cloud</title>
        <social:hashtags>#AI #Cloud #Kubernetes #OpenAPI #Techradar #Sovereignty #Fullstack #Codeberg #STACKIT</social:hashtags>
        <link rel="alternate" href="https://jdriven.com/blog/2026/04/Conflux-Fullstackathon-2026/"/>
        <published>2026-04-21T09:00:00.000Z</published>
        <updated>2026-04-21T09:00:00.000Z</updated>
        <author>
            <name>Jasper</name>
            <social:mastodon>kerfuffle@mastodon.online</social:mastodon>
            <uri>https://jdriven.com/blog/author/jasper-bogers</uri>
        </author>
        <summary type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In less than 24 hours we had 25+ developers build 10 technical diverse fullstack applications on a Kubernetes cluster
running on European cloud STACKIT, integrating via OpenAPI, using a shared AI-prompt for graphic style coherence.&lt;/p&gt;
&lt;/div&gt;</summary>
        <content type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In less than 24 hours we had 25+ developers build 10 technical diverse fullstack applications on a Kubernetes cluster
running on European cloud STACKIT, integrating via OpenAPI, using a shared AI-prompt for graphic style coherence.&lt;/p&gt;
&lt;/div&gt;
&lt;span id=&#34;more&#34;&gt;&lt;/span&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;The Conflux fullstackathon recipe&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Every year the colleagues of various Conflux brands get together over a weekend to tackle an assignment that involves
backend and frontend development in some way or another.
Though it&amp;#8217;s all in good fun, it has a competitive angle and every year the winning team puts together the assignment for
the next year.
Last year the fullstackathon involved throwing together IoT-devices and applications to liven up the office and my team
won by combining digital displays, LED-strips, motionsensors
and an SVG-based office overview to help colleagues determine which meeting room was free without having to walk there
first.
The fact that my teammate Wilco van Beijnum managed to rewrite the firmware in the motionsensors helped tip the balance
in our favor and we were asked to create an assignment for this year.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;The theme for 2026&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Much too close to the deadline of this year&amp;#8217;s fullstackathon, we held a brainstorm session to see what we could come up
with.
We found several sources of inspiration:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;We wanted to create a cyberspace, inspired by &lt;a href=&#34;https://web.archive.org/web/19961219173901/http://www2.dds.nl/&#34;&gt;the way DDS laid out their online services in the 90s&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Within Conflux we publish a &lt;a href=&#34;https://www.divotion.com/blog?tag=Tech%20Radar&#34;&gt;Divotion Tech Radar&lt;/a&gt; and a &lt;a href=&#34;https://jdriven.com/aanbod/tech-radar&#34;&gt;JDriven Tech Radar&lt;/a&gt; every half year, in which we
identify and discuss technological trends.
It would be great if we could have a cyberspace where every individual contribution could use its own tech stack.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;As can be read in the upcoming JDriven Tech Radar, we do not recommend vibecoding, but decided this event would be an
outstanding opportunity to go wild with AI-assisted coding and actually anticipate the dangerous consequences of things
breaking.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sovereignty is a major concern in both the political and the digital realm right now.
We wanted to give this attention in a lighthearted way.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the spirit of collaboration we decided to forego the competitive element and instead focus on setting a goal that
would only be met if everyone would work together.
We decided that if this event was fun enough, we wouldn&amp;#8217;t need a &#34;winner&#34; to organise next year&amp;#8217;s event; enough folks
would be inspired to step up to the task.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The resulting recipe for the weekend was as follows:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A king would task Conflux with building a digital city.
Because I&amp;#8217;m into &lt;a href=&#34;https://www.larp-platform.nl/informatie/wat-is-larp/&#34;&gt;LARP&lt;/a&gt; I decided I&amp;#8217;d roleplay the king for the occasion.
The rest of the team would be the King&amp;#8217;s Council and together we&amp;#8217;d be present at the fullstackathon event to explain the
task at hand and pivot if needed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;This digital city would have to be built in a sovereign cloud.
We looked around for European cloud providers that support a form of managed Kubernetes.
We settled on German cloud provider &lt;a href=&#34;https://stackit.com/en&#34;&gt;STACKIT&lt;/a&gt;, or commonly referred to as &#34;the Lidl cloud&#34; as it&amp;#8217;s founded by
Lidl&amp;#8217;s parent company Schwarz Group.
Because the name Lidl was taken from Ludwig Lidl, we found a name for our king: King Ludwig.
And so his city became Ludwighafen.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The king would need a castle.
We decided that we would build this ourselves, and in doing so develop a means of deploying buildings to Ludwighafen.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The King&amp;#8217;s Council would suggest services the city needed, and our colleagues would be free to team up and build
whatever they chose.
This was to be the core challenge of the fullstackathon.
It was the first time we went for a cooperative angle for this event, rather than making it a competition.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The King would have an unreasonable and authoritarian streak and intentionally be vague and change his mind on
requirements, in case the assignment would turn out to be too easy to complete.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Regardless of what the teams came up with, it would need a frontend and a backend and would have to be built into a
Docker image, uploaded to a container registry and deployed into the Kubernetes cluster we prepared for them.
It would also need health-check endpoints.
And people would have to supply the king and his council with three images for their piece: one under construction, one
finished and one burning.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock text-center&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/04/ludwighafen-voorbeeld-images.png&#34; alt=&#34;Ludwighafen example images&#34; width=&#34;50%&#34;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;The setup&lt;/h3&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;The basics: kubernetes and the means to use it&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Our organising team set up accounts in STACKIT and set up a container registry via the STACKIT web portal.
Anything any team would construct, they would have to put into a Docker image and upload it there.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;We then set up a project fullstackathon and in it, under Runtime &amp;#8594; Kubernetes Engine, we created a cluster.
Under IAM, we created a custom role for our fullstackathon participants, allowing access to the Container Registry,
adding a pod to a namespace and starting it.
We weren&amp;#8217;t very familiar with the particular access structure so we chose to be very restrictive and add permissions
later if needed.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;We used infrastructure as code to set up http-routes (using a &lt;a href=&#34;https://docs.stackit.cloud/products/runtime/kubernetes-engine/deep-dive/gateway-api/&#34;&gt;Gateway API&lt;/a&gt;), limit-ranges, resource-quotas,
and a service-account.
This was all tied to together with &lt;a href=&#34;https://kustomize.io&#34;&gt;Kustomize&lt;/a&gt; and its built-in secretGenerator in combination with STACKIT&amp;#8217;s Robot Accounts
to allow every team&amp;#8217;s pod to use the &lt;code&gt;image-puller&lt;/code&gt; Service Account to pull the uploaded Docker Image from the Container
Registry and effectively deploy and run their application in Ludwighafen.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Keys to the kingdom&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Ludwighafen was set up to be a website reachable via (the now defunct) ludwighafen.eu and any city service a team would build
would have its own namespace and a corresponding subdomain.
To keep a bit of control, we&amp;#8217;d create the namespaces when a team indicated what service they were going to build and
give them an upload key for it.
We built a form for requesting it, where they could upload their visuals too.
To ensure the image would fit the plot, we supplied an example AI-prompt for generating images in the right style and size.
We added a shell-script for generating namespaces so that we&amp;#8217;d be able to get teams going quickly during the fullstackathon.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;All any team would have to do besides dockerizing their application and pushing it to the Ludwighafen (STACKIT) Container
Registry was to create a deployment.yaml mentioning the namespace, selector, metadata and container image, and call
&lt;code&gt;kubectl apply -f deployment.yaml&lt;/code&gt; to deploy and activate their application in Ludwighafen.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Central application&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;We then decided to build the central application, that would visually be the city as well the castle at its center, and
technically be charged with checking the availability of the other services in order to show the right image for it in
the city map.
Once a team requested to build a service and supplied us with the name (for the namespace and subdomain) and the visuals
for it, the castle application would show it as under construction.
Once the application gave an HTTP 200 OK on an HTTP request to its subdomain, the castle would consider it finished and
show the appropriate visual.
If after that the service ceased to be 200 OK, it would be rendered on fire and the king would make his concerns known.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The castle application was a Python application with a simple HTML/CSS/JavaScript frontend.
And because the proof is in the pudding, we used the mechanisme we were going to unleash on our colleagues as the means
to deploy it and make it available.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock text-center&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/04/ludwighafen-kaal.png&#34; alt=&#34;Ludwighafen without any services&#34; width=&#34;50%&#34;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;We tested one demo service: it showed up in the alloted plot in the browser, and clicking it opened the frontend at
the intended subdomain.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;We did run into some snags which we documented and that ended up becoming our tutorial.
In the final minutes before the hackathon we decided to deploy that tutorial itself as an HTML page served via an Nginx
application that ran at scroll.ludwighafen.eu, styled appropriately in medieval fashion.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock text-center&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/04/ludwighafen-instructions.png&#34; alt=&#34;Instructions&#34; width=&#34;50%&#34;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;We were ready for the event.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;The hackathon&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;We kicked off the event with a presentation by me dressed as king, explaining I had heard all about digital sovereignty
being a thing.
Supposedly all colleagues in attendance were hired by me with the irrational expectation that AI would allow them to
build whatever I wanted in less than a weekend.
I presented the list of requirements that the royal council had put up for me, which as you would expect was very
superficial and lacked important details.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock text-center&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/04/ludwighafen-voorbeelddiensten.png&#34; alt=&#34;Example services&#34; width=&#34;50%&#34;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;After mentioning that people could decide for themselves how to form teams, as long as everything got built, and someone on
the council remarked that OpenAPI might be useful for integrating services, it was clear for attendants that this was going
to be a collaborative effort full of surprises.
When I explained the King likes diversity and, having seen the Tech Radars of Conflux, expected as many technologies as
possible to be used, people understood the freedom and challenges they faced.
And of course there was still the looming threat of the graphics they had to provide for their service being on fire.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;As teams formed, they sent ambassadors to the council to claim plots for services and gather requirements.
Some caught on early and came up with their own services to implement.
The King and his council, being the group that had prepared this fullstackathon, became somewhat of a platform team,
correcting access rights, activating STACKIT AI-model serving, and troubleshooting deployment issues.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;While IDEs were being set up and tools like k9s were being configured (as included in the instructions), newly-formed
teams scattered across the StayOK location where the event took place, drawing up plans on flipovers or using post-its
on windows.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Other people preferred diving straight into code, AI-bootstrapping some unknown tech to get some early results to iterate
on quickly.
Some people focused on fleshing out the idea, while others wanted to figure out how to upload to the STACKIT container
registry and deploy a pod in Ludwighafen kubernetes cluster as soon as possible to make sure they had the basics down
and would be able to deliver whatever they&amp;#8217;d produce later on.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Challenges&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;During the hackathon, people were surprisingly creative and productive off of a minimal set of requirements.
However, not everything went smooth:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;We had limited the available resources for the cluster, thinking it would force people to be more conscious of their
resource usage and collaborate on getting the most of out it.
But in reality, it was a detriment to the fun process of building things when people had to wait for over 10 minutes for
their images to be uploaded.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We had prepared the idea of some chaos engineering to see if people had autohealing and high availability.
But deployments took long and there was an abundance of ideas we saw people cramming into their services, so we decided
against frustrating that more.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We had recommended &lt;a href=&#34;https://codeberg.org&#34;&gt;Codeberg&lt;/a&gt; as a code forge. It sufficed, but had an unfortunate outage during the first day of
the hackathon.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We had explained to people to create accounts on STACKIT so they could upload images and deploy their applications.
That process had its hiccups, with STACKIT refusing to send passwords or passwords resets to people, and two developers
actually ended up locked out of their accounts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Although the use of AI for vibecoding in new languages and frameworks yielded quick and impressive results, it also
plunged teams in technical debt at record speed.
Some developers ended up having to wrestle with generated code, rewriting big parts to get desired results.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Especially the constrained resources were a miscalculation.
People consequently resorted to more local development first, and as a result one or two teams failed to deploy their
latest working application before the end, demonstrating it from their local machine instead.
A reminder that proper resource allocation for delivery pipelines and test environments is crucial for timely feedback and
the ability to deliver solutions.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;The results&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;At the end of Saturday afternoon every team showed what they had built, and it was glorious.
While they had been working and uploading, the city which was always active on a central monitor had been filling up
with interesting services.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock text-center&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/04/ludwighafen-vol-ornaat.png&#34; alt=&#34;Ludwighafen filled with services&#34; width=&#34;50%&#34;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Developers also quickly learned that if they messed up an application deployment once it had been added, it would lead
to a spectacle.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock text-center&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/04/ludwighafen-on-fire.jpg&#34; alt=&#34;Ludwighafen services on fire&#34; width=&#34;50%&#34;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Royal municipal records&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The municipal records were a service we had indicated would be crucial.
The team that picked this up had dubbed it the Blue Kremlin and went all-in on Big Brother features in a 90s style.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock text-center&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/04/ludwighafen-basisadministratie.png&#34; alt=&#34;Royal municipal records&#34; width=&#34;50%&#34;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;It featured registration of civilizans with name, age and the role &amp;amp; permissions they had.
It offered an interface for other services to determine permissions (and no other details) for certain features they
offered.
The Blue Kremlin showed ads in true 90s fashion, and these actually led to other services in the city.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Community hall&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In the community hall you could log in as a civilian and create an avatar.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock text-center&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/04/ludwighafen-buurthuis.png&#34; alt=&#34;Community hall&#34; width=&#34;50%&#34;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;It featured multiple rooms to explore, like a neighbourhood cafe that served fresh beers from the brewery, a
chatroom where you could request songs for the radiostation to play and a dark room which required a special permission,
requested from the Blue Kremlin.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Bank&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The bank allowed the creation of accounts for every registered civilian and also interfaced with the Blue Kremlin for
checking that that civilian was indeed permitted to do so.
Civilizans could make payments and transfer funds to each other and get an overview of their transactions.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock text-center&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/04/ludwighafen-bank.png&#34; alt=&#34;Bank&#34; width=&#34;50%&#34;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Visually, the bank website had every feature frontend developers have nightmares of, like a bouncing logo with
a lensflare, animations and misaligned boxes.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;AirDnD&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The AirDnD service did not offer a way to rent rooms for guests of Ludwighafen.
Instead, it offered cheap uncomfortable dungeons to sleep in, some even featuring a dragon.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock text-center&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/04/ludwighafen-airdnd.png&#34; alt=&#34;AirDnD&#34; width=&#34;50%&#34;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;There was also the possibility for citizens to put up and rent out their own dungeons to visitors of the city.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Brewery&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The brewery was a neat gamified service for brewing bear.
You could pick ingredients, set the temperature and choose a fermentation method to end up with unique beers.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock text-center&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/04/ludwighafen-brouwerij.png&#34; alt=&#34;Brewery&#34; width=&#34;50%&#34;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;These beers then went up for sale and became available in the Ludwighafen community hall.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Radiostation&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Unfortunately, the radiostation service frontend was not caught on camera, as this was one team that had decided to
focus entirely on local development first and ended up not being able to deploy it in time.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock text-center&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/04/ludwighafen-radiostation-fire.png&#34; alt=&#34;Ludwighafen radiostation on fire&#34; width=&#34;25%&#34;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock text-center&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/04/ludwighafen-radiostation-finished.png&#34; alt=&#34;Ludwighafen radiostation finished&#34; width=&#34;25%&#34;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The radiostation could play songs from Spotify, as requested in the radiostation chat, or via the community hall.
Between songs, AI-rendered commercial audiotracks spoke highly of Ludwighafen, its king and the available services.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;PortHub&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The PortHub was the harbour and shipyard of Ludwighafen.
Nothing but a means of uploading videos sharing the wholesome appreciation for hard labour and beautiful ships.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock text-center&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/04/ludwighafen-porthub.png&#34; alt=&#34;PortHub&#34; width=&#34;50%&#34;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Powerplant&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The idea behind the powerplant was that it kept an eye on the amount of services in the Ludwighafen cluster and calculated
an amount of power needed to run those.
If the power demand was too high, it would raise a loud alarm and eventually kill off a random pod.
To increase the power, a small game was introduced reminiscent of the dinosaur jumping over cactuses in FireFox, but
it instead had a knight jumping over beer barrels, each jump counting towards added power to run the city.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock text-center&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/04/ludwighafen-stroomcentrale.png&#34; alt=&#34;Powerplant&#34; width=&#34;50%&#34;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Actually killing off pods is something we implored the team to not implement, for reasons mentioned above.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Palace of Soestdijk&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;As the hackathon participants hacked, they became thirsty.
Every time they ordered drinks, they&amp;#8217;d tell the bartender at the hostel a little more about their ideas and efforts.
Eventually the bartender, a proud inhabitant of Soest, requested Ludwighafen to feature the Palace of Soestdijk.
We were happy to oblige.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock text-center&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/04/ludwighafen-soestdijk.png&#34; alt=&#34;Palace of Soestdijk&#34; width=&#34;50%&#34;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Arcade hall&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;At the end of the presentations of the participants of the fullstackathon, the royal council showed that it had also
secretly built an arcadehall with a powerful feature.
Now that the work was complete and people were about to head home, we felt it was the right time to show we had planned
some chaos engineering.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock text-center&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/04/ludwighafen-arcade.png&#34; alt=&#34;Arcade&#34; width=&#34;50%&#34;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The arcade hall allowed you to play Doom.
But it was a special version in which level 1 spawned demons that represented all the pods running in the Ludwighafen
kubernetes cluster.
Any demon shot meant a pod killed.
As we demonstrated it and the buildings in the Ludwighafen city map caught fire, it was a testament to the fact that
autohealing indeed did work and buildings would go back to being 200 OK.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock text-center&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/04/ludwighafen-kill-pods.jpg&#34; alt=&#34;Ludwighafen torn down&#34; width=&#34;50%&#34;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;That is, until we shot a demon that was some crucial pod of the kubernetes management plane itself, and everything
grinded to a halt.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;A fitting end of a successful fullstackathon.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;Tech Stack&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;As said, the King wanted diversity.
Here is a list of technologies employed during the 24 hours in which we built Ludwighafen in all its glory.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Platform&lt;/h4&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;STACKIT cloud&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Kubernetes&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Docker&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;k9s&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Kustomize&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Envoy&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Nginx&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;IDE&lt;/h4&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;JetBrains IntelliJ&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Cursor&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;VSCode&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Backend&lt;/h4&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Kotlin&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Java&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Spring Boot&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Thymeleaf&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Rust&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Python&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Frontend&lt;/h4&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;HTML&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CSS&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;JavaScript&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;TypeScript&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Vue&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;HTMX&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Angular&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;React&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;AI&lt;/h4&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Big Pickle&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Kiro&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Google Gemini&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Proton Lumo&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Claude Sonnet&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;OpenCode&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Forge&lt;/h4&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Codeberg&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;GitHub&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;BitBucket&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;The cost&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;From the start of March, when we set up the STACKIT account, created the fullstackathon project and the container registry
and activated the kubernetes engine, through the hackathon itself on the last weekend of March when we created accounts, uploaded application images
and pulled in npm and maven dependencies and started all those applications, and generated STACKIT AI-tokens,
we burned approximately 250 euros.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Every day afterwards that we kept the entire cluster running we spent another 25 euros.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;STACKIT offers hibernation, which means servers running in the kubernetes cluster are turned off, but the cluster itself
remains operational along with its persistent volumes and container registry.
This reduced the cost to 15 euros a day and allowed us quickly getting everything back up and running in case we wanted to
show off Ludwighafen or iterate some more on it.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;The aftermath&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In the weeks following the fullstackathon, several people were still inspired and continued adding features.
The royal municipal records was upgraded with a true Big Brother gridview of the city, showing the location of every
logged in citizen.
The bank, built in HTMX, received some additional features.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;It turns out the concept of Ludwighafen, a place running in the familiar kubernetes but on a totally new cloud, where
the sky is the limit as far as technical choices go, was an inspiration for exploring and trying out new technology.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;At the time of writing, Ludwighafen has been torn down completely, ready to be reconstructed on a different cloud or
on-prem.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;Reference list&lt;/h3&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://web.archive.org/web/19961219173901/http://www2.dds.nl/&#34;&gt;the way DDS laid out their online services in the 90s&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.divotion.com/blog?tag=Tech%20Radar&#34;&gt;Divotion Tech Radar&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://jdriven.com/aanbod/tech-radar&#34;&gt;JDriven Tech Radar&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.larp-platform.nl/informatie/wat-is-larp/&#34;&gt;LARP&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://stackit.com/en&#34;&gt;STACKIT&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.stackit.cloud/products/runtime/kubernetes-engine/deep-dive/gateway-api/&#34;&gt;Gateway API&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://codeberg.org&#34;&gt;Codeberg&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://kustomize.io&#34;&gt;Kustomize&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;</content>
        <category term="Sovereignty" scheme="https://jdriven.com/blog/category/Sovereignty/" />
        <category term="Cloud" scheme="https://jdriven.com/blog/category/Sovereignty/Cloud/" />
        <category term="Fullstack Development" scheme="https://jdriven.com/blog/category/Sovereignty/Cloud/Fullstack-Development/" />
        <category term="AI" scheme="https://jdriven.com/blog/tag/AI/" />
        <category term="Cloud" scheme="https://jdriven.com/blog/tag/Cloud/" />
        <category term="Kubernetes" scheme="https://jdriven.com/blog/tag/Kubernetes/" />
        <category term="OpenAPI" scheme="https://jdriven.com/blog/tag/OpenAPI/" />
        <category term="Techradar" scheme="https://jdriven.com/blog/tag/Techradar/" />
        <category term="Sovereignty" scheme="https://jdriven.com/blog/tag/Sovereignty/" />
        <category term="Fullstack" scheme="https://jdriven.com/blog/tag/Fullstack/" />
        <category term="Codeberg" scheme="https://jdriven.com/blog/tag/Codeberg/" />
        <category term="STACKIT" scheme="https://jdriven.com/blog/tag/STACKIT/" />
    </entry>
    <entry>
        <id>https://jdriven.com/blog/2026/04/Nushell-Niceties-Sorting-Version-Values-With-Semver-Ordering/</id>
        <title>Nushell Niceties: Sorting Version Values With Semver Ordering</title>
        <social:hashtags>#Nushell</social:hashtags>
        <link rel="alternate" href="https://jdriven.com/blog/2026/04/Nushell-Niceties-Sorting-Version-Values-With-Semver-Ordering/"/>
        <published>2026-04-21T04:55:55.000Z</published>
        <updated>2026-04-21T04:55:55.000Z</updated>
        <author>
            <name>mrhaki</name>
            <social:mastodon>mrhaki@mastodon.online</social:mastodon>
            <social:bluesky>mrhaki.com</social:bluesky>
            <uri>https://jdriven.com/blog/author/mrhaki</uri>
        </author>
        <summary type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The semver Nushell plugin can be used to work with string values as semver type as you can see in a &lt;a href=&#34;https://jdriven.com/blog/2026/04/Nushell-Niceties-Transform-Values-Into-Semver-Types/&#34;&gt;previous post&lt;/a&gt;. You can use the &lt;code&gt;semver sort&lt;/code&gt; command to sort string values with ordering rules for semantic versions. With natural ordering of string values a value of &lt;code&gt;10.0.1&lt;/code&gt; is placed before &lt;code&gt;2.1.0&lt;/code&gt;, but if you use &lt;code&gt;semver sort&lt;/code&gt; the ordering will be correct. The command will look at all the parts of the semver type. So a major version of &lt;code&gt;2&lt;/code&gt; is placed before &lt;code&gt;10&lt;/code&gt;. If the major version part is the same than the minor part is used for ordering and so on. To sort in descending order you can use the option &lt;code&gt;--reverse&lt;/code&gt; or the short option &lt;code&gt;-r&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;</summary>
        <content type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The semver Nushell plugin can be used to work with string values as semver type as you can see in a &lt;a href=&#34;https://jdriven.com/blog/2026/04/Nushell-Niceties-Transform-Values-Into-Semver-Types/&#34;&gt;previous post&lt;/a&gt;. You can use the &lt;code&gt;semver sort&lt;/code&gt; command to sort string values with ordering rules for semantic versions. With natural ordering of string values a value of &lt;code&gt;10.0.1&lt;/code&gt; is placed before &lt;code&gt;2.1.0&lt;/code&gt;, but if you use &lt;code&gt;semver sort&lt;/code&gt; the ordering will be correct. The command will look at all the parts of the semver type. So a major version of &lt;code&gt;2&lt;/code&gt; is placed before &lt;code&gt;10&lt;/code&gt;. If the major version part is the same than the minor part is used for ordering and so on. To sort in descending order you can use the option &lt;code&gt;--reverse&lt;/code&gt; or the short option &lt;code&gt;-r&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;span id=&#34;more&#34;&gt;&lt;/span&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In the following example a list of version values is sorted with the &lt;code&gt;semver sort&lt;/code&gt; command:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-nu hljs&#34; data-lang=&#34;nu&#34;&gt;use std/assert

# After installing the nu_plugin_semver plugin and
# adding it to the plugin registry you can use
# the plugin for Nushell code.
plugin use semver

# `semver sort` uses correct ordering for version values.
(assert equal
        ([&#39;10.0.2&#39; &#39;2.3.1&#39; &#39;1.10.1&#39; &#39;2.3.1-beta.3&#39; &#39;2.3.1-alpha.1&#39;] | semver sort)
        [&#39;1.10.1&#39;
         &#39;2.3.1-alpha.1&#39;
         &#39;2.3.1-beta.3&#39;
         &#39;2.3.1&#39;
         &#39;10.0.2&#39;])

# Without `semver sort` the natural ordering is used, but that is not correct
# for version values. E.g. 10.0.2 is before 2.3.1.
(assert equal
        ([&#39;10.0.2&#39; &#39;2.3.1&#39; &#39;1.10.1&#39; &#39;2.3.1-beta.3&#39; &#39;2.3.1-alpha.1&#39;] | sort)
        [&#39;1.10.1&#39;
         &#39;10.0.2&#39;
         &#39;2.3.1&#39;
         &#39;2.3.1-alpha.1&#39;
         &#39;2.3.1-beta.3&#39;])


# Using the option `--reverse` (shorthand `-r`) to reverse the sorting order.
(assert equal
        ([&#39;10.0.2&#39; &#39;2.3.1&#39; &#39;1.10.1&#39; &#39;2.3.1-beta.3&#39; &#39;2.3.1-alpha.1&#39;] | semver sort --reverse)
        [&#39;10.0.2&#39;
         &#39;2.3.1&#39;
         &#39;2.3.1-beta.3&#39;
         &#39;2.3.1-alpha.1&#39;
         &#39;1.10.1&#39;])&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Written with Nushell 0.111.0.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://blog.mrhaki.com/2026/03/nushell-niceties-sorting-version-values.html&#34;&gt;Original post&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;</content>
        <category term="Nushell" scheme="https://jdriven.com/blog/category/Nushell/" />
        <category term="Nushell" scheme="https://jdriven.com/blog/tag/Nushell/" />
    </entry>
    <entry>
        <id>https://jdriven.com/blog/2026/04/Lazygit/</id>
        <title>Lazygit</title>
        <social:hashtags>#Git #Tools #DevOps</social:hashtags>
        <link rel="alternate" href="https://jdriven.com/blog/2026/04/Lazygit/"/>
        <published>2026-04-17T04:30:00.000Z</published>
        <updated>2026-04-17T04:30:00.000Z</updated>
        <author>
            <name>Ronald</name>
            <social:twitter>kqosh1</social:twitter>
            <uri>https://jdriven.com/blog/author/ronald-koster</uri>
        </author>
        <summary type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Arguably the most popular version control system is Git. Many developers use the command-line version alongside
a Git plugin in their favorite IDE. Now those work just fine, but did you know there is also a very nice
TUI (Text-based User Interface, alternately Terminal User Interface) for Git called &lt;a href=&#34;https://github.com/jesseduffield/lazygit&#34;&gt;Lazygit&lt;/a&gt;.
It is a very cool tool. Read on for more information.&lt;/p&gt;
&lt;/div&gt;</summary>
        <content type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Arguably the most popular version control system is Git. Many developers use the command-line version alongside
a Git plugin in their favorite IDE. Now those work just fine, but did you know there is also a very nice
TUI (Text-based User Interface, alternately Terminal User Interface) for Git called &lt;a href=&#34;https://github.com/jesseduffield/lazygit&#34;&gt;Lazygit&lt;/a&gt;.
It is a very cool tool. Read on for more information.&lt;/p&gt;
&lt;/div&gt;
&lt;span id=&#34;more&#34;&gt;&lt;/span&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;How to Start and Install&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;After &lt;a href=&#34;https://github.com/jesseduffield/lazygit?tab=readme-ov-file#installation&#34;&gt;installation&lt;/a&gt; it starts really fast,
just type &lt;code&gt;lazygit&lt;/code&gt; in the your terminal in your project directory and you get something like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/04/lazygit_screenshot.png&#34; alt=&#34;lazygit_screenshot.png&#34;&gt;
&lt;/div&gt;
&lt;div class=&#34;title&#34;&gt;Figure 1. Lazygit Screenshot&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Usage&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;As you can see it gives a very nice overview of your Git workflow and repository status.
And as with any TUI navigating and executing commands can be done extremely quickly and easily using your keyboard only
(see &lt;a href=&#34;https://github.com/jesseduffield/lazygit/tree/master/docs/keybindings&#34;&gt;keybindings&lt;/a&gt;). The keybindings can also
be popped up with the &#39;?&#39; key. On top of that Lazygit also responds to your mouse.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;imageblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;img src=&#34;/blog/uploads/2026/04/lazygit_keybindings.png&#34; alt=&#34;lazygit_keybindings.png&#34;&gt;
&lt;/div&gt;
&lt;div class=&#34;title&#34;&gt;Figure 2. Lazygit Keybindings&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;All in all, it is a very handy tool and a great addition to Git on the command-line and your IDE Git plugin.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</content>
        <category term="Git" scheme="https://jdriven.com/blog/category/Git/" />
        <category term="Tools" scheme="https://jdriven.com/blog/category/Git/Tools/" />
        <category term="Version Control System" scheme="https://jdriven.com/blog/category/Git/Tools/Version-Control-System/" />
        <category term="DevOps" scheme="https://jdriven.com/blog/category/Git/Tools/Version-Control-System/DevOps/" />
        <category term="Git" scheme="https://jdriven.com/blog/tag/Git/" />
        <category term="Tools" scheme="https://jdriven.com/blog/tag/Tools/" />
        <category term="DevOps" scheme="https://jdriven.com/blog/tag/DevOps/" />
    </entry>
    <entry>
        <id>https://jdriven.com/blog/2026/04/PKI-in-a-Nutshell/</id>
        <title>PKI in a Nutshell</title>
        <social:hashtags>#Security #PKI #PublicKeyInfrastructure #Certificates #PublicKey #PrivateKey #Keystore #Truststore</social:hashtags>
        <link rel="alternate" href="https://jdriven.com/blog/2026/04/PKI-in-a-Nutshell/"/>
        <published>2026-04-14T05:30:00.000Z</published>
        <updated>2026-04-14T05:30:00.000Z</updated>
        <author>
            <name>Ronald</name>
            <social:twitter>kqosh1</social:twitter>
            <uri>https://jdriven.com/blog/author/ronald-koster</uri>
        </author>
        <summary type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;This blog briefly describes theoretically how Public Key Infrastructure (PKI) works.
It also introduces the key concepts used in PKI.
This is done by describing encryption, decryption, hashing, signing, and authentication using mathematical notations.&lt;/p&gt;
&lt;/div&gt;</summary>
        <content type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;This blog briefly describes theoretically how Public Key Infrastructure (PKI) works.
It also introduces the key concepts used in PKI.
This is done by describing encryption, decryption, hashing, signing, and authentication using mathematical notations.&lt;/p&gt;
&lt;/div&gt;
&lt;span id=&#34;more&#34;&gt;&lt;/span&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3&gt;PKI in a Nutshell&lt;/h3&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Intro&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Given an asymmetric encryption algorithm E and accompanying Decryption algorithm D.
It uses a key pair (&lt;em&gt;K&lt;sub&gt;e&lt;/sub&gt;, K&lt;sub&gt;d&lt;/sub&gt;&lt;/em&gt;) to encrypt a plain text message &lt;em&gt;x&lt;/em&gt; into a cipher text &lt;em&gt;y&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;encryption: E(&lt;em&gt;K&lt;sub&gt;e&lt;/sub&gt;, x&lt;/em&gt;) = &lt;em&gt;y&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;decyption: D(&lt;em&gt;K&lt;sub&gt;d&lt;/sub&gt;, y&lt;/em&gt;) = &lt;em&gt;x&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Alice and Bob&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Suppose Alice and Bob want to exchange encrypted messages with each other, and they also want to sign
the messages so that they can be sure the messages they receive are from each other indeed, and not from some
malignant third party.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Alice owns two key pairs.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;keyPairA1 ={&lt;em&gt;K&lt;sub&gt;A1e&lt;/sub&gt;, K&lt;sub&gt;A1d&lt;/sub&gt;&lt;/em&gt;}&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;keyPairA2 = {&lt;em&gt;K&lt;sub&gt;A2e&lt;/sub&gt;, K&lt;sub&gt;A2d&lt;/sub&gt;&lt;/em&gt;}&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Alice publishes the keys &lt;em&gt;K&lt;sub&gt;A1e&lt;/sub&gt;&lt;/em&gt; and &lt;em&gt;K&lt;sub&gt;A2d&lt;/sub&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Bob thas two key pairs as well:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;keyPairB1 = {&lt;em&gt;K&lt;sub&gt;B1e&lt;/sub&gt;, K&lt;sub&gt;B1d&lt;/sub&gt;&lt;/em&gt;}&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;keyPairB2 = {&lt;em&gt;K&lt;sub&gt;B2e&lt;/sub&gt;, K&lt;sub&gt;B2d&lt;/sub&gt;&lt;/em&gt;}&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;And he publishes &lt;em&gt;K&lt;sub&gt;B1e&lt;/sub&gt;&lt;/em&gt; and &lt;em&gt;K&lt;sub&gt;B2d&lt;/sub&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The keys that are published are called &lt;strong&gt;public keys&lt;/strong&gt;, the ones you keep for yourself are called &lt;strong&gt;private keys&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Key pairs are kept in a &lt;strong&gt;keystore&lt;/strong&gt;. Trusted public keys, or the certificates thereof (see below),
are kept in a &lt;strong&gt;truststore&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Encryption&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Bob can now send an encrypted message to Alice using her &lt;strong&gt;public encryption key&lt;/strong&gt; &lt;em&gt;K&lt;sub&gt;A1e&lt;/sub&gt;&lt;/em&gt; with&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;E(&lt;em&gt;K&lt;sub&gt;A1e&lt;/sub&gt;, x&lt;/em&gt;) = &lt;em&gt;y&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Which can only be decrypted by Alice with her &lt;strong&gt;private decryption key&lt;/strong&gt; &lt;em&gt;K&lt;sub&gt;A1d&lt;/sub&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;D(&lt;em&gt;K&lt;sub&gt;A1d&lt;/sub&gt;, y&lt;/em&gt;) = &lt;em&gt;x&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;And vice versa Alice can send encrypted message to Bob using the public key &lt;em&gt;K&lt;sub&gt;B1e&lt;/sub&gt;&lt;/em&gt; from Bob.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Signing&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Bob can use his &lt;strong&gt;private signing key&lt;/strong&gt; &lt;em&gt;K&lt;sub&gt;B2e&lt;/sub&gt;&lt;/em&gt; to sign his encrypted messages.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Given a hashing algorithm H&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;em&gt;h&lt;/em&gt; = H(&lt;em&gt;y&lt;/em&gt;) = &lt;em&gt;hash of y&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Next define&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;em&gt;s&lt;/em&gt; = S(&lt;em&gt;y&lt;/em&gt;) = E(&lt;em&gt;K&lt;sub&gt;B2e&lt;/sub&gt;&lt;/em&gt;, H(&lt;em&gt;y&lt;/em&gt;)) = &lt;em&gt;signature&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Bob sends (&lt;em&gt;y&lt;/em&gt;, &lt;em&gt;s&lt;/em&gt;) to Alice.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Now Alice can verify the cipher text &lt;em&gt;y&lt;/em&gt; is from Bob by applying the verify operation V using Bob&amp;#8217;s &lt;strong&gt;public verification key&lt;/strong&gt; &lt;em&gt;K&lt;sub&gt;B2d&lt;/sub&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;V(&lt;em&gt;s&lt;/em&gt;) = D(&lt;em&gt;K&lt;sub&gt;B2d&lt;/sub&gt;, s&lt;/em&gt;) = &lt;em&gt;h&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;And she can also calculate &lt;em&gt;h&lt;/em&gt; herself from the received &lt;em&gt;y&lt;/em&gt;. Both hashes must be equal.
Since only the owner of &lt;em&gt;K&lt;sub&gt;B2e&lt;/sub&gt;&lt;/em&gt; could have sent the signature &lt;em&gt;s&lt;/em&gt; encrypted in this way she knows this
message is from Bob.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;NB The same is true if Bob had signed the plain text &lt;em&gt;x&lt;/em&gt; instead of the cipher text &lt;em&gt;y&lt;/em&gt;. The choice is somewhat arbitrary.
Albeit, that signing the cipher text &lt;em&gt;y&lt;/em&gt; is a bit safer. Because when signing &lt;em&gt;x&lt;/em&gt; and Alice&amp;#8217;s private key has somehow
been acquired by a malignant third party Mallory, Mallory can decrypt &lt;em&gt;y&lt;/em&gt; and reencrypt it with his
own private key and reuse the signature. When &lt;em&gt;y&lt;/em&gt; is signed, he cannot reuse the signature.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Vice versa Alice can sign her message to Bob using her signing key &lt;em&gt;K&lt;sub&gt;A2e&lt;/sub&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Certificates&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;What if Alice and Bob have no secure channel to exchange their public keys? Well suppose they do both have a secure channel with
a third party CA (Certification Authority) whom they trust, which means they trust the CA&amp;#8217;s public verification key &lt;em&gt;K&lt;sub&gt;CAd&lt;/sub&gt;&lt;/em&gt;.
They offer their public keys to CA to have them signed.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;For example Alice offers her public encryption key to be signed by CA&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;S&lt;sub&gt;CA&lt;/sub&gt;(&lt;em&gt;K&lt;sub&gt;A1e&lt;/sub&gt;&lt;/em&gt;) = E(&lt;em&gt;K&lt;sub&gt;CAe&lt;/sub&gt;&lt;/em&gt;, H(&lt;em&gt;K&lt;sub&gt;A1e&lt;/sub&gt;&lt;/em&gt;)) = &lt;em&gt;s&lt;sub&gt;A1e&lt;/sub&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;And Alice publishes&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;em&gt;c&lt;sub&gt;A1e&lt;/sub&gt;&lt;/em&gt; = {&lt;em&gt;K&lt;sub&gt;A1e&lt;/sub&gt;&lt;/em&gt;, S&lt;sub&gt;CA&lt;/sub&gt;(&lt;em&gt;K&lt;sub&gt;A1e&lt;/sub&gt;&lt;/em&gt;)} = {&lt;em&gt;K&lt;sub&gt;A1e&lt;/sub&gt;&lt;/em&gt;, &lt;em&gt;s&lt;sub&gt;A1e&lt;/sub&gt;&lt;/em&gt;} = &lt;em&gt;certificate of K&lt;sub&gt;A1e&lt;/sub&gt; signed by&lt;/em&gt; CA&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Bob can now verify the key is from Alice by calculating&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;V&lt;sub&gt;CA&lt;/sub&gt;(&lt;em&gt;s&lt;sub&gt;A1e&lt;/sub&gt;&lt;/em&gt;) = D(&lt;em&gt;K&lt;sub&gt;CAd&lt;/sub&gt;&lt;/em&gt;, &lt;em&gt;s&lt;sub&gt;A1e&lt;/sub&gt;&lt;/em&gt;) = &lt;em&gt;h&lt;sub&gt;v&lt;/sub&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;H(&lt;em&gt;K&lt;sub&gt;A1e&lt;/sub&gt;&lt;/em&gt;) = &lt;em&gt;h&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The following should be true: &lt;em&gt;h&lt;sub&gt;v&lt;/sub&gt;&lt;/em&gt; = &lt;em&gt;h&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The same can be done for the other public keys of Alice and Bob. So by publishing certificates of their
public keys instead of the keys alone they can safely exchange messages without having a secure
channel to exchange their public keys directly.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;For convenience CA does not publish its verification key alone, but a self-signed certificate of it&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;em&gt;c&lt;sub&gt;CAd&lt;/sub&gt;&lt;/em&gt; = {&lt;em&gt;K&lt;sub&gt;CAd&lt;/sub&gt;&lt;/em&gt;, S&lt;sub&gt;CA&lt;/sub&gt;(&lt;em&gt;K&lt;sub&gt;CAd&lt;/sub&gt;&lt;/em&gt;)}&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect3&#34;&gt;
&lt;h4&gt;Chain of Trust&lt;/h4&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Above is an example of a chain of trust. Alice and Bob trust CA. This a chain of length 2. Longer chains are
more common. For example when Alice and Bob use a certificate from CA&lt;sub&gt;2&lt;/sub&gt;, which is signed by CA&lt;sub&gt;1&lt;/sub&gt;, which is signed by
a self-signed certificate of CA&lt;sub&gt;0&lt;/sub&gt;=CA&lt;sub&gt;root&lt;/sub&gt;. They both trust CA&lt;sub&gt;0&lt;/sub&gt;, and Alice has her keys signed by CA&lt;sub&gt;2&lt;/sub&gt;.
For example the chain for her public encryption key:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;em&gt;c&lt;sub&gt;A1e&lt;/sub&gt;&lt;/em&gt; = {&lt;em&gt;K&lt;sub&gt;A1e&lt;/sub&gt;&lt;/em&gt;, &lt;em&gt;s&lt;sub&gt;A1e&lt;/sub&gt;&lt;/em&gt;} = {&lt;em&gt;K&lt;sub&gt;A1e&lt;/sub&gt;&lt;/em&gt;, S&lt;sub&gt;CA2&lt;/sub&gt;(&lt;em&gt;K&lt;sub&gt;A1e&lt;/sub&gt;&lt;/em&gt;)}&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;em&gt;c&lt;sub&gt;CA2d&lt;/sub&gt;&lt;/em&gt; = {&lt;em&gt;K&lt;sub&gt;CA2d&lt;/sub&gt;&lt;/em&gt;, &lt;em&gt;s&lt;sub&gt;CA2d&lt;/sub&gt;&lt;/em&gt;} = {&lt;em&gt;K&lt;sub&gt;CA2d&lt;/sub&gt;&lt;/em&gt;, S&lt;sub&gt;CA1&lt;/sub&gt;(&lt;em&gt;K&lt;sub&gt;CA2d&lt;/sub&gt;&lt;/em&gt;)}&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;em&gt;c&lt;sub&gt;CA1d&lt;/sub&gt;&lt;/em&gt; = {&lt;em&gt;K&lt;sub&gt;CA1d&lt;/sub&gt;&lt;/em&gt;, &lt;em&gt;s&lt;sub&gt;CA1d&lt;/sub&gt;&lt;/em&gt;} = {&lt;em&gt;K&lt;sub&gt;CA1d&lt;/sub&gt;&lt;/em&gt;, S&lt;sub&gt;CA0&lt;/sub&gt;(&lt;em&gt;K&lt;sub&gt;CA1d&lt;/sub&gt;&lt;/em&gt;)}&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;em&gt;c&lt;sub&gt;CA0d&lt;/sub&gt;&lt;/em&gt; = {&lt;em&gt;K&lt;sub&gt;CA0d&lt;/sub&gt;&lt;/em&gt;, &lt;em&gt;s&lt;sub&gt;CA0d&lt;/sub&gt;&lt;/em&gt;} = {&lt;em&gt;K&lt;sub&gt;CA0d&lt;/sub&gt;&lt;/em&gt;, S&lt;sub&gt;CA0&lt;/sub&gt;(&lt;em&gt;K&lt;sub&gt;CA0d&lt;/sub&gt;&lt;/em&gt;)}&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;So Bob trusts the public encryption key of Alice, &lt;em&gt;K&lt;sub&gt;A1e&lt;/sub&gt;&lt;/em&gt;, because it is signed by CA&lt;sub&gt;2&lt;/sub&gt;, which is
signed by CA&lt;sub&gt;1&lt;/sub&gt;, which is signed by CA&lt;sub&gt;0&lt;/sub&gt;, which he trusts.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;It is common practice to send the entire chain upon publishing/sending of one&amp;#8217;s certificate.
So usually one keeps the entire chain for each certificate in one&amp;#8217;s &lt;strong&gt;keystore&lt;/strong&gt;.
Since the public key is part of the certificate a keystore usually contains
entries with in it a private key and the associated certificate chain.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The certificates one trusts are kept a so called &lt;strong&gt;truststore&lt;/strong&gt;.
The sender&amp;#8217;s chain of certificates must end at a certificate in one&amp;#8217;s truststore.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</content>
        <category term="PKI" scheme="https://jdriven.com/blog/category/PKI/" />
        <category term="Public Key Infrastructure" scheme="https://jdriven.com/blog/category/PKI/Public-Key-Infrastructure/" />
        <category term="Security" scheme="https://jdriven.com/blog/category/PKI/Public-Key-Infrastructure/Security/" />
        <category term="Certificates" scheme="https://jdriven.com/blog/category/PKI/Public-Key-Infrastructure/Security/Certificates/" />
        <category term="Security" scheme="https://jdriven.com/blog/tag/Security/" />
        <category term="PKI" scheme="https://jdriven.com/blog/tag/PKI/" />
        <category term="Public Key Infrastructure" scheme="https://jdriven.com/blog/tag/Public-Key-Infrastructure/" />
        <category term="Certificates" scheme="https://jdriven.com/blog/tag/Certificates/" />
        <category term="Public Key" scheme="https://jdriven.com/blog/tag/Public-Key/" />
        <category term="Private Key" scheme="https://jdriven.com/blog/tag/Private-Key/" />
        <category term="Keystore" scheme="https://jdriven.com/blog/tag/Keystore/" />
        <category term="Truststore" scheme="https://jdriven.com/blog/tag/Truststore/" />
    </entry>
    <entry>
        <id>https://jdriven.com/blog/2026/04/Nushell-Niceties-Bumping-Semantic-Version/</id>
        <title>Nushell Niceties: Bumping Semantic Version</title>
        <social:hashtags>#Nushell</social:hashtags>
        <link rel="alternate" href="https://jdriven.com/blog/2026/04/Nushell-Niceties-Bumping-Semantic-Version/"/>
        <published>2026-04-14T04:52:23.000Z</published>
        <updated>2026-04-14T04:52:23.000Z</updated>
        <author>
            <name>mrhaki</name>
            <social:mastodon>mrhaki@mastodon.online</social:mastodon>
            <social:bluesky>mrhaki.com</social:bluesky>
            <uri>https://jdriven.com/blog/author/mrhaki</uri>
        </author>
        <summary type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In a &lt;a href=&#34;https://jdriven.com/blog/2026/04/Nushell-Niceties-Transform-Values-Into-Semver-Types/&#34;&gt;previous blogpost&lt;/a&gt; you can learn about the &lt;code&gt;semver&lt;/code&gt; command in Nushell to transform a string value into a semver type. With the &lt;code&gt;semver bump&lt;/code&gt; command you can increase one of the components of the semver type. For example to increase the major version part you can use &lt;code&gt;semver bump major&lt;/code&gt;. This command will also update the minor and patch parts if needed. The result is a semver type and you can use &lt;code&gt;into value&lt;/code&gt; to transform it to a string type.&lt;/p&gt;
&lt;/div&gt;</summary>
        <content type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In a &lt;a href=&#34;https://jdriven.com/blog/2026/04/Nushell-Niceties-Transform-Values-Into-Semver-Types/&#34;&gt;previous blogpost&lt;/a&gt; you can learn about the &lt;code&gt;semver&lt;/code&gt; command in Nushell to transform a string value into a semver type. With the &lt;code&gt;semver bump&lt;/code&gt; command you can increase one of the components of the semver type. For example to increase the major version part you can use &lt;code&gt;semver bump major&lt;/code&gt;. This command will also update the minor and patch parts if needed. The result is a semver type and you can use &lt;code&gt;into value&lt;/code&gt; to transform it to a string type.&lt;/p&gt;
&lt;/div&gt;
&lt;span id=&#34;more&#34;&gt;&lt;/span&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In the following example several of the &lt;code&gt;semver bump&lt;/code&gt; commands are used:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-nu hljs&#34; data-lang=&#34;nu&#34;&gt;use std/assert

# After installing the nu_plugin_semver plugin and
# adding it to the plugin registry you can use
# the plugin for Nushell code.
plugin use semver

# Transform string to semver value.
let version = &#39;4.0.2&#39;

# Bumping major part of version by adding 1 to the current value.
assert equal ($version | semver bump major | into value) &#39;5.0.0&#39;

# Bumping minor part by adding 1 to the value.
# The option `--ignore-errors` makes sure when an error occurs the
# original input value is returned. The shorthand `-i` is also valid.
assert equal ($version | semver bump minor --ignore-errors | into value) &#39;4.1.0&#39;

# Bumping patch part by adding 1 to the value.
assert equal ($version | semver bump patch | into value) &#39;4.0.3&#39;

# Bumping to a release candidate version, patch is unchanged.
assert equal ($version | semver bump rc | into value) &#39;4.0.2-rc.1&#39;

# Bumping to a next alpha version by adding 1 to patch value and
# pre-release part `alpha.1`.
assert equal ($version | semver bump alpha | into value) &#39;4.0.3-alpha.1&#39;

# Bumping to a next beta version by adding 1 to patch value and
# pre-release part `beta.1`.
assert equal ($version | semver bump beta | into value) &#39;4.0.3-beta.1&#39;

# Using `bump release` will remove the pre (release) part of semver value.
assert equal (&#39;4.0.3-rc.1&#39; | semver bump release | into value) &#39;4.0.3&#39;


# The same bump commands can be used for a semver type input.
let full_version = &#39;4.0.2-rc.1+build-20260205&#39; | into semver

assert equal ($full_version | semver bump major | into value) &#39;5.0.0&#39;
assert equal ($full_version | semver bump minor | into value) &#39;4.1.0&#39;
assert equal ($full_version | semver bump patch | into value) &#39;4.0.2+build-20260205&#39;
assert equal ($full_version | semver bump rc | into value) &#39;4.0.2-rc.2+build-20260205&#39;
assert equal ($full_version | semver bump release | into value) &#39;4.0.2+build-20260205&#39;


# The `semver bump` command support the `--build-metadata` (or shorthand `-b`)
# option to add build metadata to a semver or string value.
(assert equal
        (&#39;4.2.8&#39; | semver bump minor --build-metadata &#39;build-20260205&#39; | into value)
        &#39;4.3.0+build-20260205&#39;)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Written with Nushell 0.111.0.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://blog.mrhaki.com/2026/03/nushell-niceties-bumping-semantic.html&#34;&gt;Original post&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;</content>
        <category term="Nushell" scheme="https://jdriven.com/blog/category/Nushell/" />
        <category term="Nushell" scheme="https://jdriven.com/blog/tag/Nushell/" />
    </entry>
    <entry>
        <id>https://jdriven.com/blog/2026/04/Nushell-Niceties-Transform-Values-Into-Semver-Types/</id>
        <title>Nushell Niceties: Transform Values Into Semver Types</title>
        <social:hashtags>#Nushell</social:hashtags>
        <link rel="alternate" href="https://jdriven.com/blog/2026/04/Nushell-Niceties-Transform-Values-Into-Semver-Types/"/>
        <published>2026-04-07T04:45:40.000Z</published>
        <updated>2026-04-07T04:45:40.000Z</updated>
        <author>
            <name>mrhaki</name>
            <social:mastodon>mrhaki@mastodon.online</social:mastodon>
            <social:bluesky>mrhaki.com</social:bluesky>
            <uri>https://jdriven.com/blog/author/mrhaki</uri>
        </author>
        <summary type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Nushell can be extended with plugins to have more functionality or types that are not part of standard Nushell. If you want to work with string values that are actually semantic version values (&lt;a href=&#34;https://semver.org&#34; class=&#34;bare&#34;&gt;https://semver.org&lt;/a&gt;) you can use the &lt;a href=&#34;https://github.com/abusch/nu_plugin_semver&#34;&gt;Nushell SemVer plugin&lt;/a&gt;. The plugin must be added to Nushell by using the command &lt;code&gt;plugin add &amp;lt;location of plugin&amp;gt;&lt;/code&gt;. You can check with &lt;code&gt;plugin list&lt;/code&gt; command if the plugin is available. This command also shows commands that the plugin adds to Nushell.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The command &lt;code&gt;into semver&lt;/code&gt; can be used to convert string values into a semver type. The semver type has 5 properties: &lt;code&gt;major&lt;/code&gt;, &lt;code&gt;minor&lt;/code&gt;, &lt;code&gt;patch&lt;/code&gt;, &lt;code&gt;pre&lt;/code&gt; and &lt;code&gt;build&lt;/code&gt;. You can use dot notation to get the values for these properties or use the &lt;code&gt;get&lt;/code&gt; command. In the following command a string value is transformed to a semver type: &lt;code&gt;let v = &#39;4.0.2&#39; | into semver&lt;/code&gt;. And with &lt;code&gt;$v.major&lt;/code&gt; you can extract the major part of the semver value and it returns &lt;code&gt;4&lt;/code&gt;.&lt;br&gt;
Records with the keys &lt;code&gt;major&lt;/code&gt;, &lt;code&gt;minor&lt;/code&gt;, &lt;code&gt;patch&lt;/code&gt;, &lt;code&gt;pre&lt;/code&gt; and &lt;code&gt;build&lt;/code&gt; can be transformed to a semver string with the &lt;code&gt;semver from-record&lt;/code&gt; command. And to transform a semver type to a record you can use the command &lt;code&gt;semver into-record&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;</summary>
        <content type="html">&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Nushell can be extended with plugins to have more functionality or types that are not part of standard Nushell. If you want to work with string values that are actually semantic version values (&lt;a href=&#34;https://semver.org&#34; class=&#34;bare&#34;&gt;https://semver.org&lt;/a&gt;) you can use the &lt;a href=&#34;https://github.com/abusch/nu_plugin_semver&#34;&gt;Nushell SemVer plugin&lt;/a&gt;. The plugin must be added to Nushell by using the command &lt;code&gt;plugin add &amp;lt;location of plugin&amp;gt;&lt;/code&gt;. You can check with &lt;code&gt;plugin list&lt;/code&gt; command if the plugin is available. This command also shows commands that the plugin adds to Nushell.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The command &lt;code&gt;into semver&lt;/code&gt; can be used to convert string values into a semver type. The semver type has 5 properties: &lt;code&gt;major&lt;/code&gt;, &lt;code&gt;minor&lt;/code&gt;, &lt;code&gt;patch&lt;/code&gt;, &lt;code&gt;pre&lt;/code&gt; and &lt;code&gt;build&lt;/code&gt;. You can use dot notation to get the values for these properties or use the &lt;code&gt;get&lt;/code&gt; command. In the following command a string value is transformed to a semver type: &lt;code&gt;let v = &#39;4.0.2&#39; | into semver&lt;/code&gt;. And with &lt;code&gt;$v.major&lt;/code&gt; you can extract the major part of the semver value and it returns &lt;code&gt;4&lt;/code&gt;.&lt;br&gt;
Records with the keys &lt;code&gt;major&lt;/code&gt;, &lt;code&gt;minor&lt;/code&gt;, &lt;code&gt;patch&lt;/code&gt;, &lt;code&gt;pre&lt;/code&gt; and &lt;code&gt;build&lt;/code&gt; can be transformed to a semver string with the &lt;code&gt;semver from-record&lt;/code&gt; command. And to transform a semver type to a record you can use the command &lt;code&gt;semver into-record&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;span id=&#34;more&#34;&gt;&lt;/span&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In the following example different string values are transformed and from a semver type or record:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlightjs highlight&#34;&gt;&lt;code class=&#34;language-nu hljs&#34; data-lang=&#34;nu&#34;&gt;use std/assert

# After installing the nu_plugin_semver plugin and
# adding it to the plugin registry you can use
# the plugin for Nushell code.
plugin use semver

# With `into semver` you can transform a string
# into a semver value with the fields
# major, minor, patch, pre and build.
let version = &#39;4.0.2&#39; | into semver

assert equal $version.major 4
assert equal $version.minor 0
assert equal $version.patch 2
assert equal ($version | get patch) 2

# Type is semver and no longer a string type.
assert equal ($version | describe) semver

# A full version with all parts.
# The pre (release) part is after the patch and - up until the +.
# The build part is everything after the +.
let full_version = &#39;4.0.2-rc.1+build-20260205&#39; | into semver

assert equal $full_version.major 4
assert equal $full_version.minor 0
assert equal $full_version.patch 2
assert equal $full_version.pre &#39;rc.1&#39;
assert equal $full_version.build &#39;build-20260205&#39;

# A version with major, minor, patch and build part.
let build_version = &#39;4.0.2+build-20260205&#39; | into semver

assert equal $build_version.build &#39;build-20260205&#39;
assert equal $build_version.major 4
assert equal $build_version.minor 0
assert equal $build_version.patch 2


# Using `semver to-record` to transform a semver value or string
# to a record with the keys major, minor, patch, pre and build.
assert equal ($version | semver to-record) {
    major: 4 minor: 0 patch: 2 pre: &#39;&#39; build: &#39;&#39;
}
assert equal (&#39;1.2.3&#39; | semver to-record) {
    major: 1 minor: 2 patch: 3 pre: &#39;&#39; build: &#39;&#39;
}
assert equal (&#39;4.0.2-rc.1+build-20260205&#39; | semver to-record) {
    major: 4 minor: 0 patch: 2 pre: &#39;rc.1&#39; build: &#39;build-20260205&#39;
}

# Using `semver from-record` to transform a record with keys
# major, minor, patch, pre and build to a semver value.
(assert equal
        ({major: 4 minor: 0 patch: 2 pre: &#39;&#39; build: &#39;&#39;} | semver from-record)
        &#39;4.0.2&#39;)
(assert equal
        ({major: 4 minor: 0 patch: 2 pre: &#39;rc.1&#39; build: &#39;build-20260205&#39;} | semver from-record)
        &#39;4.0.2-rc.1+build-20260205&#39;)


# A list of string value can be transformed to a list of semver values.
(assert equal ([&#39;4.0.2-rc.1+build-20260205&#39; &#39;1.2.3&#39;] | into semver)
    [(&#39;4.0.2-rc.1+build-20260205&#39; | into semver) (&#39;1.2.3&#39; | into semver)])&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Written with Nushell 0.110.0.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://blog.mrhaki.com/2026/02/nushell-niceties-transform-values-into.html&#34;&gt;Original post&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;</content>
        <category term="Nushell" scheme="https://jdriven.com/blog/category/Nushell/" />
        <category term="Nushell" scheme="https://jdriven.com/blog/tag/Nushell/" />
    </entry>
</feed>
