# codefionn — full content
> Full text of every post on https://codefionn.eu, newest first. Companion to [/llms.txt](https://codefionn.eu/llms.txt), following https://llmstxt.org. Posts are written in English and German.
# The bad design of LLM APIs
> What building an LLM gateway taught me about the state of AI
*Published on 2026-10-04 · en · https://codefionn.eu/the-bad-design-of-llm-apis/*
I'm currently developing many different AI-enabled applications and
specifically created [llmleaf](https://github.com/codefionn/llmleaf), an AI
gateway proxy that unifies and enriches all kinds of LLM API providers.
During this I had some issues with these interfaces and sometimes with their
documentation. This article covers the issues that the AI providers somehow
ignore.
## SSE
How would you implement a bidirectional communication protocol? Single
requests? Custom binary protocol? Maybe WebSockets?
The answer chosen by the industry was of course
SSE. It's a web standard for streaming
events from the server to the client, which is good. Crucially, it doesn't
stream the other way around, which is bad. Maybe this was a good decision in the
early ChatGPT days, but the post-Opus 4.8 era needs something different.
This has two issues. When the client has to send messages back to the server,
which in the age of agentic development includes a lot of tool call results, a
completely new request has to be made to the server. This is made worse by
prompt caching being a requirement for cost reasons and by thinking being hidden
or encrypted.
When the new request is sent to answer a tool call, the API has to infer the
last server response from the context, probably via hashing. Once it's
identified, caching works properly and the user hopefully pays less for tokens
that were already processed. The implementor has to ensure that the
messages sent are detected as the same ones sent previously.
There are even special API features that try to work around this, e.g.
Anthropic's `cache_control` or OpenAI's `previous_response_id`.
All this reconnecting has a latency cost, which would not be paid by proper
implementations. If you want to experience this, just use Codex with the
OpenAI subscription. It already uses WebSockets.
Over SSE, every tool call means a new request with the whole historyOver a WebSocket, the connection stays open and only new input is sent
## MCPs
The previous MCP specs were so bad
that the 2026-07-28 spec had to fix them. FYI: the previous specs required
stateful connections, which made stuff like letting your customers' agents read
your documentation over MCP way harder and more resource intensive than it
needed to be. The 2026-07-28 spec finally makes MCP stateless.
Another issue is that the previous specs made every agent session spawn its own
MCP connections, which made 3 or more agents very costly with some larger MCP
servers.
## The list endpoint
AI providers have endpoints for listing supported models. The issue: they often
don't provide necessary information. In the worst case, you will just get model
ids, names and release dates.
OpenAI's model list: no context window, no pricing, no capabilities
But there's a lot of information required for implementing an AI-enabled
application: context window length, max output tokens, pricing, supported
parameters and capabilities like thinking, input and output modalities (e.g.
can receive an image), automatic context window compression (summarization).
This is why providers like OpenRouter are an easy solution for applications
that support "any" provider, because they provide essential information.
## The future
I hope that more providers see how great WebSockets are in agentic workflows
and support them more. MCP got fixed with the 2026-07-28 spec, but it will
probably take years for the old MCP programs to disappear. List endpoints most
likely won't get fixed due to lock-in effects, where you have to optimize your
software for a specific provider.
Providers don't have many reasons to fix some of these issues, so gateway
proxies like [llmleaf](https://github.com/codefionn/llmleaf) or
[Portkey AI Gateway](https://github.com/Portkey-AI/gateway) will have to fill
the gaps.
## Further resources
- [Using server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)
- [Speeding up agentic workflows with WebSockets in the Responses API](https://openai.com/index/speeding-up-agentic-workflows-with-websockets/)
- [OpenAI WebSocket mode](https://developers.openai.com/api/docs/guides/websocket-mode)
- [The 2026-07-28 MCP specification](https://blog.modelcontextprotocol.io/posts/2026-07-28/)
---
# Das schlechte Design von LLM-APIs
> Was mir die Entwicklung eines LLM-Gateways über den Stand von KI beigebracht hat
*Veröffentlicht am 2026-10-04 · de · https://codefionn.eu/das-schlechte-design-von-llm-apis/*
Ich entwickle zurzeit viele verschiedene KI-Anwendungen und habe dafür
[llmleaf](https://github.com/codefionn/llmleaf) gebaut, einen KI-Gateway-Proxy,
der alle möglichen LLM-API-Anbieter vereinheitlicht und mit zusätzlichen
Informationen anreichert.
Dabei hatte ich einige Probleme mit diesen Schnittstellen und manchmal auch mit
ihren Informationen. Dieser Artikel behandelt die Probleme, die die KI-Anbieter
irgendwie ignorieren.
## SSE
Wie würdest du ein bidirektionales Kommunikationsprotokoll umsetzen? Einzelne
Anfragen? Ein selbst erstelltes Binärprotokoll? Vielleicht WebSockets?
Die Antwort der Branche war natürlich
SSE. Das ist ein Webstandard, um Events
vom Server zum Client zu streamen, was gut ist. Entscheidend ist aber, dass es
nicht in die andere Richtung streamt, und das ist schlecht. Vielleicht war das
in den frühen ChatGPT-Tagen eine gute Entscheidung, aber die Zeit nach Opus 4.8
braucht etwas anderes.
Das führt zu zwei Problemen. Wenn der Client Nachrichten an den Server
zurückschicken muss, und im Zeitalter agentischer Entwicklung sind das viele
Tool-Call-Ergebnisse, muss ein komplett neuer Request an den Server gehen.
Verschlimmert wird das dadurch, dass Prompt-Caching aus Kostengründen Pflicht
ist und Thinking versteckt oder verschlüsselt wird.
Wenn der neue Request einen Tool-Call beantwortet, muss die API die letzte
Server-Antwort aus dem Kontext ableiten, vermutlich über Hashing. Sobald sie
gefunden ist, funktioniert das Caching richtig und der Nutzer zahlt hoffentlich
weniger für Tokens, die schon verarbeitet wurden. Der Entwickler muss dafür
sorgen, dass die gesendeten Nachrichten als dieselben erkannt werden, die schon
vorher gesendet wurden.
Es gibt sogar spezielle API-Funktionen, die versuchen, das zu umgehen, z. B.
`cache_control` von Anthropic oder `previous_response_id` von OpenAI.
Dieses ständige Neuverbinden kostet Latenz, die eine vernünftige Umsetzung nicht
hätte. Wer das selbst erleben will, nutzt einfach Codex mit dem
OpenAI-Abonnement. Das verwendet bereits WebSockets.
Mit SSE bedeutet jeder Tool-Call einen neuen Request mit dem ganzen VerlaufMit einem WebSocket bleibt die Verbindung offen und nur neuer Input wird geschickt
## MCPs
Die bisherigen MCP-Spezifikationen
waren so schlecht, dass die Spezifikation vom 2026-07-28 sie reparieren musste.
Zur Info: Die bisherigen Spezifikationen haben zustandsbehaftete Verbindungen
verlangt. Das hat Dinge wie den Zugriff der Agenten deiner Kunden auf deine
Dokumentation über MCP viel schwieriger und ressourcenhungriger gemacht als
nötig. Die Spezifikation vom 2026-07-28 macht MCP endlich zustandslos.
Ein weiteres Problem war, dass mit den bisherigen Spezifikationen jede
Agenten-Session ihre eigenen MCP-Verbindungen aufbauen musste. Mit einigen
größeren MCP-Servern wurden dadurch schon drei oder mehr Agenten sehr teuer.
## Der List-Endpunkt
KI-Anbieter haben Endpunkte, die die unterstützten Modelle auflisten. Das
Problem: Sie liefern oft nicht die nötigen Informationen. Im schlimmsten Fall
bekommst du nur Modell-IDs, Namen und Veröffentlichungsdaten.
Die Modellliste von OpenAI: kein Kontextfenster, keine Preise, keine Fähigkeiten
Für eine KI-Anwendung braucht man aber viel mehr Informationen: Länge des
Kontextfensters, maximale Output-Tokens, Preise, unterstützte Parameter und
Fähigkeiten wie Thinking, Input- und Output-Modalitäten (z. B. ob das Modell
Bilder annehmen kann) und automatische Kontextkomprimierung (Zusammenfassung).
Deshalb sind Anbieter wie OpenRouter eine einfache Lösung für Anwendungen, die
"jeden" Anbieter unterstützen, denn sie liefern die wesentlichen Informationen.
## Die Zukunft
Ich hoffe, dass mehr Anbieter erkennen, wie gut WebSockets für agentische
Workflows sind, und sie stärker unterstützen. MCP wurde mit der Spezifikation
vom 2026-07-28 repariert, aber es wird wohl Jahre dauern, bis die alten
MCP-Programme verschwinden. List-Endpunkte werden wahrscheinlich wegen
Lock-in-Effekten nicht repariert, weil man seine Software auf einen bestimmten
Anbieter optimieren muss.
Die Anbieter haben wenig Gründe, einige dieser Probleme zu beheben. Deshalb
müssen Gateway-Proxys wie [llmleaf](https://github.com/codefionn/llmleaf) oder
[Portkey AI Gateway](https://github.com/Portkey-AI/gateway) die Lücken füllen.
## Weiterführende Links
- [Server-sent events verwenden](https://developer.mozilla.org/de/docs/Web/API/Server-sent_events/Using_server-sent_events)
- [Speeding up agentic workflows with WebSockets in the Responses API](https://openai.com/index/speeding-up-agentic-workflows-with-websockets/) (Englisch)
- [OpenAI WebSocket mode](https://developers.openai.com/api/docs/guides/websocket-mode) (Englisch)
- [Die MCP-Spezifikation vom 2026-07-28](https://blog.modelcontextprotocol.io/posts/2026-07-28/) (Englisch)
---
# The age of small personalized software is here
> The age of small personalized software is here and it's yours to exploit
*Published on 2026-03-06 · en · https://codefionn.eu/the-age-of-small-personalized-software-is-here/*
It started for everyone with the introduction of ChatGPT, this new wave of LLMs
and other AI models. The generation of text, incrementally even better
generation of text with other capabilities allows writing software big and
small, allowing developers to move faster and everyday people to write small
programs.
The past software development cycles have show us that with every introduction
of new technologies that make software development easier, more software is
written. We had the introduction of textual assembler, Basic, programming
languages, easier ways to edit code and open source.
Each step made code easier to write, and more of it got written
The introduction of AI coding agents made code cheaper—a lot cheaper. This
means competing with basic features and feature count is not actually that
productive. Large software projects have to survive for a long time and must
compete on quality.
Fast, well working software that captures the user's intent correctly is a joy
to witness. We can take the same amount of time to implement features, but use
our newly acquired time to improve quality and longevity, while maybe being a
bit faster still. And those items in your backlog? Maybe you can fix them now.
Our users can also use AI. Auto translation, more intelligent automations,
speech, image recognition and even writing one-off extensions inside of
software products. Let them experience what we are experiencing right now.
We as software developers have to focus on delivering robust and joyful
software that has good guardrails and allows our users to focus on the hard and
human stuff.
---
# Das Zeitalter kleiner persönlicher Software ist da
> Das Zeitalter kleiner personalisierter Software ist da und es steht dir zur Verfügung
*Veröffentlicht am 2026-03-06 · de · https://codefionn.eu/das-zeitalter-kleiner-personalisierter-software-ist-da/*
Es begann für alle mit der Einführung von ChatGPT, diese neue Welle von LLMs
und anderen KI-Modellen. Die Generierung von Text, schrittweise immer bessere
Textgenerierung mit weiteren Fähigkeiten ermöglicht es, Software großer und
kleiner Art zu schreiben, produktivere Entwickler und den Menschen dort draußen
kleine Programme zu schreiben.
Die vergangenen Softwareentwicklungszyklen haben uns gezeigt, dass mit jeder
Einführung neuer Technologien, die die Softwareentwicklung erleichtern, mehr
Software geschrieben wird. Wir hatten die Einführung von textuellem Assembler,
Basic, Programmiersprachen, einfachere Möglichkeiten Code zu bearbeiten und
Open Source.
Jeder Schritt machte Code einfacher, und es wurde mehr davon geschrieben
Die Einführung von KI-Coding-Agenten hat Code billiger gemacht – viel billiger.
Das bedeutet, dass der Wettbewerb mit grundlegende Funktionen und einer
Funktionsanzahl nicht wirklich produktiv ist. Große Softwareprojekte müssen
lange überleben und per Qualität konkurrieren.
Schnelle, gut funktionierende Software, die die Absicht der Benutzer korrekt
erfasst, ist eine Freude zu sehen Wir können die gleiche Zeit für die
Implementierung von Funktionen aufwenden, aber unsere neu gewonnene Zeit
nutzen, um Qualität und Langlebigkeit zu verbessern, während wir vielleicht
sogar noch etwas schneller werden. Und die Punkte in deinem Backlog? Vielleicht
kannst du diese jetzt beheben.
Auch unsere Benutzer können KI nutzen. Automatische Übersetzung, intelligentere
Automatisierungen, Spracherkennung, Bilderkennung und sogar das Schreiben von
einmaligen Erweiterungen innerhalb von Softwareprodukten. Lass sie erleben, was
wir gerade jetzt erleben.
Wir als Softwareentwickler müssen uns darauf konzentrieren, robuste und
freudschaffene Software zu liefern, die gute Schutzmechanismen bietet und unseren
Benutzern ermöglicht, sich auf das Schwierige und Menschliche zu konzentrieren.
---
# Problems with the current LLMs
> Problems that I encountered programming a code llm tui app
*Published on 2025-12-11 · en · https://codefionn.eu/problems-with-the-current-llms/*
I recently developed a TUI for generating code via LLMs in my free time called
[scriptschnell](https://github.com/codefionn/scriptschnell). This gave me some
insight into what currently is lacking in current LLMs.
## Speed
After using Cerebras and Groq (Groq with **q**) to a lesser extent, the speed
that OpenAI's models gpt-5.1-codex or gpt-5.1-codex-mini provide is lacking.
Code generation requires a lot of looking up current implementation details,
creating or changing files and then validating the result. All this requires a
lot of tokens (in my experience just searching through the codebase takes at
least 20k tokens).
Some code generation applications like
[Windsurf use a significantly faster model](https://www.cerebras.ai/blog/case-study-cognition-x-cerebras)
to speed up some tasks like exploring the codebase.
## Tool calls
You can tell that many models are trained to use specific tool calls. E.g.
when prompting Kimi K2 Instruct with just "ls" it tries to use a tool
call called `shell` even though that doesn't exist.
Kimi K2 Instruct reaching for a tool it has never been given
More specifically, it required a lot of trial and error to make LLM models
write more complex programs for my golang sandbox tool call (e.g. building
an application and extracting key errors with a summarize method).
## Built-in assumptions
Model performance currently seems best when using built-in assumptions baked
in during the training process. This is especially problematic when using newer
external libraries than the training knowledge cut-off date.
## Context window woes
The current context windows of state-of-the-art models are at least 128k tokens.
But when some part of this is already used by the system prompt and tool call
descriptions and then the investigation of the codebase, the context window
is too little.
The biggest problem here is that model performance seems to drop off a cliff when
using large parts of the given context window.
Where the context window goes, and where the model stops listening
E.g. when using Claude Opus 4.5, the latest, greatest and pricey model at the
time of writing, it seems to love to ignore the codebase style when 3/4 of its
context window is used up.
The compaction of the context window to allow seamlessly endless sessions is
also hard to steer to success. Transmitting information about code style and
problems solved over the summarization boundary feels like a roll of the dice. Also,
somehow telling the model that's only half the story leads to failure, because
then the model begins going through the codebase again, using up precious
tokens.
## Vision
Vision still doesn't really work. Even simple tasks like creating an HTML
file or SVG file from a screenshot make the model seem incompetent (e.g.
creating an SVG from a company logo).
## Closing words
I think we still have a long road ahead of us with the current state of
transformer models.
When you create agents for specific tasks, you have to optimize your program
for the specific model family.
We've come really far with the current LLM technology and I think a lot of "hacks"
on top of the current implementations can still improve the current state
significantly.
## Sources
- [Case Study - Cognition x Cerebras](https://www.cerebras.ai/blog/case-study-cognition-x-cerebras)
- [Context Length Alone Hurts LLM Performance Despite Perfect Retrieval](https://arxiv.org/abs/2510.05381)
- [Insights into LLM Long-Context Failures: When Transformers Know but Don't Tell](https://arxiv.org/abs/2406.14673)
- [Vision language models are blind: Failing to translate detailed visual features into words](https://arxiv.org/abs/2407.06581)
- [Evaluating LLMs at Detecting Errors in LLM Responses](https://arxiv.org/abs/2404.03602)
---
# Probleme mit den aktuellen LLMs
> Probleme, auf die ich bei der Programmierung einer Code-LLM-TUI-App gestoßen bin
*Veröffentlicht am 2025-12-11 · de · https://codefionn.eu/probleme-mit-jetzigen-llms/*
Ich habe in meiner Freizeit kürzlich eine TUI zur Code-Generierung über LLMs entwickelt namens
[scriptschnell](https://github.com/codefionn/scriptschnell). Dies gab mir einige
Einblicke darin, was aktuellen LLMs derzeit fehlt.
## Geschwindigkeit
Nach der Nutzung von Cerebras und Groq (mit **q**) in geringerem Umfang, lässt die
Geschwindigkeit, die OpenAI's Modelle gpt-5.1-codex oder gpt-5.1-codex-mini bieten, zu wünschen übrig.
Die Code-Generierung erfordert viel Nachschlagen aktueller Implementierungsdetails,
Erstellen oder Ändern von Dateien und anschließendes Validieren des Ergebnisses. All dies
erfordert viele Tokens (nach meiner Erfahrung allein das Durchsuchen der Codebasis benötigt
mindestens 20k Tokens).
Einige Code-Generierungs-Anwendungen wie
[Windsurf nutzen ein deutlich schnelleres Modell](https://www.cerebras.ai/blog/case-study-cognition-x-cerebras),
um einige Aufgaben wie das Erkunden der Codebasis zu beschleunigen.
## Tool-Calls
Man kann erkennen, dass viele Modelle darauf trainiert sind, spezifische Tool-Calls zu verwenden.
Z.B. versucht Kimi K2 Instruct bei der Eingabe von nur "ls" einen Tool-Call namens `shell`
zu verwenden, obwohl dieser nicht existiert.
Kimi K2 Instruct greift nach einem Tool, das es nie bekommen hat
Genauer gesagt erforderte es viele Versuche und Irrtümer, um LLM-Modelle dazu zu bringen,
komplexere Programme für meinen Golang-Sandbox-Tool-Call zu schreiben (z.B. Erstellen
einer Anwendung und Extrahieren von Schlüsselfehlern mit einer Summarize-Methode).
## Eingebaute Annahmen
Die Modellleistung scheint derzeit am besten zu sein, wenn man eingebaute Annahmen verwendet,
die während des Trainingsprozesses eingeprägt wurden. Dies ist besonders problematisch,
wenn man neuere externe Bibliotheken verwendet als den Wissens-Cutoff-Zeitpunkt des Trainings.
## Probleme mit dem Kontextfenster
Die aktuellen Kontextfenster sind bei State-of-the-Art-Modellen mindestens 128k groß.
Aber wenn bereits ein Teil davon durch den System-Prompt und Tool-Beschreibungen
belegt ist und anschließend die Untersuchung der Codebasis erfolgt, ist das Kontextfenster
zu klein.
Das größte Problem hierbei ist, dass die Modellleistung scheinbar abrupt einbricht,
wenn große Teile des gegebenen Kontextfensters genutzt werden.
Wohin das Kontextfenster geht und ab wann das Modell nicht mehr zuhört
z.B. bei Claude Opus 4.5, dem neuesten, größten und teuersten Modell zum
Zeitpunkt des Schreibens, scheint es zu lieben, den Code-Stil der Codebasis zu
ignorieren, wenn 3/4 seines Kontextfensters verbraucht sind.
Die Komprimierung des Kontextfensters, um nahtlos endlose Sitzungen zu ermöglichen,
ist auch schwer erfolgreich zu steuern. Die Übertragung von Informationen über Code-Stil
und gelöste Probleme über die Zusammenfassungs-Grenze fühlt sich wie ein Glücksspiel an.
Auch das Modell nur die halbe Geschichte zu erzählen, führt zum Scheitern, da
dann das Modell beginnt, die Codebasis erneut zu durchsuchen und wertvolle Tokens verbraucht.
## Vision
Vision funktioniert immer noch nicht wirklich. Selbst einfachere Aufgaben wie das Erstellen
einer HTML-Datei oder SVG-Datei aus einem Screenshot machen das Modell inkompetent wirken
(z.B. Erstellen eines SVG aus einem Firmenlogo).
## Abschließende Worte
Ich denke, wir haben mit dem aktuellen Zustand der Transformer-Modelle noch einen langen
Weg vor uns.
Wenn man Agenten für spezifische Aufgaben erstellt, muss man sein Programm für die
spezifische Modellfamilie optimieren.
Wir sind mit der aktuellen LLM-Technologie wirklich weit gekommen und ich
denke, dass viele Hacks, die auf den aktuellen Implementierungen aufsetzen, den
derzeitigen Zustand noch erheblich verbessern können.
## Quellen
- [Case Study - Cognition x Cerebras](https://www.cerebras.ai/blog/case-study-cognition-x-cerebras)
- [Context Length Alone Hurts LLM Performance Despite Perfect Retrieval](https://arxiv.org/abs/2510.05381)
- [Insights into LLM Long-Context Failures: When Transformers Know but Don't Tell](https://arxiv.org/abs/2406.14673)
- [Vision language models are blind: Failing to translate detailed visual features into words](https://arxiv.org/abs/2407.06581)
- [Evaluating LLMs at Detecting Errors in LLM Responses](https://arxiv.org/abs/2404.03602)
---
# Why did software become so complex?
> Why did software become so complex? Is it ECMAScript?
*Published on 2025-07-19 · en · https://codefionn.eu/why-did-software-become-so-complex/*
> Why did software become so complex? Is it ECMAScript?
Software isn't the only thing that got complex: z = 3 + 2i
## Change in expectations
>> [Software is eating the world. - Marc Andreessen](https://www.wsj.com/articles/SB10001424053111903480904576512250915629460)
Oh, hello. Did you just try to center a div horizontally and vertically today?
Did Visual Studio decide that the error is your whole program, just to be
restarted and the error simply not existing anymore? Did you have to restart
your language server, because it had enough for now?
So why did software become so complex? I think the answer lies in the changing
times and expectations of software.
When I got my first computer (probably about 2006-2007), there was still the
saying
>> save often, save early
this is not expected behavior anymore and isn't part of the zeitgeist anymore.
People expect auto save. Toggle a checkbox, change everything **immediately**.
Otherwise, they will call your customer support.
Software was an addon, now it is **required**. Schools managed their timetables and
enrolled pupils with paperwork and a lot of organization. Parents can now look
up their child's timetable and cancelled lessons, if a teacher called in
sick. You probably use specialized software and not just excel tables or basic
text editor.
Before software was nice thing, that speed up your workflow (kinda like LLMs
today) or made [big things possible](https://en.wikipedia.org/wiki/ENIAC),
but today it exists, and there's no way
around it. Your corporate files are immediately stored in a central repository
and can be searched for information. This requires at least an intranet, file
syncing, version management and authorization.
You file your taxes with a computer (and maybe a smartphone?) over the
internet.
When editing a person in a CMS system, maybe just fetching the data and editing
it isn't enough. The data may have to be live updated if someone else edits it
at the same time concurrently.
Before just people had to talk or write to each other to get things done as
different groups, now your local specialties of software products have to
communicate with each other too.
## Change in risk profiles
>> [To express our gratitude, your next cup of coffee or late night snack is on us! - CrowdStrike](https://www.bbc.com/news/articles/ce58p0048r0o)
Today your line of code can cause
[someone to be mistangly be accused of fraud and false accounting](https://en.wikipedia.org/wiki/British_Post_Office_scandal),
sometimes leading to someone taking their own life.
The stock marked was a lot slower a few decades ago. Today milliseconds are the
line between profit and loosing money. Software trades and
[one wrong, untested configuration can bankrupt an entire company](https://en.wikipedia.org/wiki/Knight_Capital_Group)
or [take a huge chunk of the digital world down](https://en.wikipedia.org/wiki/2024_CrowdStrike-related_IT_outages)
and with it parts of the real world.
## Change in legal requirements
>> [The internet is new land for all of us - Angela Merkel, 2013](https://www.zeit.de/digital/internet/2013-06/merkel-das-internet-ist-fuer-uns-alle-neuland)
Politics in some parts of the world also discovered, that people can do pretty
shitty stuff with software, too (or most times just want to spy on everything
that moves).
Software has to follow the law contrary to tech bro opinion (or they just buy a
seat in government).
In the EU you must have a privacy policy, informing users about the shitty
things you do with their data. You have the right to be forgotten and download
your data (including but not limited to moderation and internal comments on
your person).
## Change in scope, everywhere
Software has to be reliable, constantly updated, always evolving, never go
down and still be somewhat affordable.
This means software based on databases with a file system that runs in three
different datacenters, logging, observability, end-to-end testing and live
migrations.
Software doesn't just have to work for a specific demographic, software must be
designed for everyone and everything between 0 and at least a 100 years old
(your grandma and the kids using that Tiktok thing). It has to work on
Apple computers, Windows arm and x86-64, Linux, smartphones and maybe on a tv.
Color palettes cannot be random, because some people may not be able to
distinguished between a different set of colors. Your software must be able to
show, talk and [braille](https://en.wikipedia.org/wiki/Braille).
Software has nearly no limits and can be deployed everywhere.
Software must be able to become old, we're talking decades and soon and maybe
even now half a century.
## Closing words
In summary, software become a big part of the real world and has to do a lot more
real world things and deal with them.
Of course your blog probably shouldn't be written with *Next.js*.
---
# Warum ist Software so komplex geworden?
> Warum ist Software eigentlich so komplex geworden? Ist es ECMAScript?
*Veröffentlicht am 2025-07-19 · de · https://codefionn.eu/warum-ist-software-so-komplex-geworden/*
> Warum wurde eigentlich Software so komplex? Ist es ECMAScript?
Nicht nur Software ist komplex: z = 3 + 2i
## Wandel der Erwartungen
>> [Software is eating the world. - Marc Andreessen](https://www.wsj.com/articles/SB10001424053111903480904576512250915629460)
Oh, hallo. Hast du heute versucht, ein div horizontal und vertikal zu zentrieren?
Hat Visual Studio entschieden, dass der Fehler dein ganzes Programm ist, nur um
neu gestartet zu werden und der Fehler existiert einfach nicht mehr? Musstest du
deinen Language Server neu starten, weil er genug hatte?
Warum wurde Software also so komplex? Ich denke, die Antwort liegt in den sich
wandelnden Zeiten und Erwartungen an Software.
Als ich meinen ersten Computer bekommen habe (wahrscheinlich um 2006-2007), gab es
noch den Spruch
>> save often, save early
das ist kein erwartetes Verhalten mehr und gehört nicht mehr zum Zeitgeist.
Menschen erwarten automatisches Speichern. Checkbox umschalten, **sofort**
alles ändern. Ansonsten rufen sie Ihren Kundensupport an.
Software war ein Zusatz, jetzt ist sie **erforderlich**. Schulen verwalteten ihre
Stundenpläne und meldeten Schüler mit Papier und viel Organisation an. Eltern
können jetzt den Stundenplan ihres Kindes und ausgefallene Stunden nachsehen,
wenn ein Lehrer sich krank gemeldet hat. Du verwendest wahrscheinlich spezialisierte
Software und nicht nur Excel-Tabellen oder einen einfachen Texteditor.
Früher war Software etwas Nettes, das deinen Workflow beschleunigte (ähnlich
wie LLMs heute) oder [große Dinge möglich machte](https://en.wikipedia.org/wiki/ENIAC),
aber heute existiert sie, und es gibt keinen Weg daran vorbei. Deine
Unternehmensdateien werden sofort in einem zentralen Repository gespeichert und
können nach Informationen durchsucht werden. Das erfordert mindestens ein Intranet,
Dateisynchronisation, Versionsverwaltung und Autorisierung.
Du reichst deine Steuern mit einem Computer (und vielleicht einem Smartphone?)
über das Internet ein.
Beim Bearbeiten einer Person in einem CMS-System reicht es vielleicht nicht aus,
nur die Daten abzurufen und zu bearbeiten. Die Daten müssen möglicherweise live
aktualisiert werden, wenn jemand anderes sie zur gleichen Zeit gleichzeitig bearbeitet.
Früher mussten Menschen nur miteinander sprechen oder schreiben, um Dinge als
verschiedene Gruppen zu erledigen, jetzt müssen die lokalen Spezialitäten von
Softwareprodukten auch miteinander kommunizieren.
## Wandel der Risikoprofile
>> [To express our gratitude, your next cup of coffee or late night snack is on us! - CrowdStrike](https://www.bbc.com/news/articles/ce58p0048r0o)
Heute kann Ihre Codezeile dazu führen, dass
[jemand fälschlicherweise des Betrugs und der falschen Buchführung beschuldigt wird](https://en.wikipedia.org/wiki/British_Post_Office_scandal),
was manchmal dazu führt, dass jemand sich das Leben nimmt.
Der Aktienmarkt war vor ein paar Jahrzehnten viel langsamer. Heute sind Millisekunden
die Grenze zwischen Gewinn und Geldverlust. Software handelt und
[eine falsche, ungetestete Konfiguration kann ein ganzes Unternehmen in den Bankrott treiben](https://en.wikipedia.org/wiki/Knight_Capital_Group)
oder [einen großen Teil der digitalen Welt zum Erliegen bringen](https://en.wikipedia.org/wiki/2024_CrowdStrike-related_IT_outages)
und mit ihr Teile der realen Welt.
## Wandel der rechtlichen Anforderungen
>> [Das Internet ist für uns alle Neuland - Angela Merkel, 2013](https://www.zeit.de/digital/internet/2013-06/merkel-das-internet-ist-fuer-uns-alle-neuland)
Die Politik in einigen Teilen der Welt hat auch entdeckt, dass Menschen mit Software
ziemlich beschissene Sachen machen können (oder meistens nur alles ausspionieren wollen,
was sich bewegt).
Software muss sich an das Gesetz halten, entgegen der Meinung der Tech-Bros (oder
die kaufen sich einfach einen Sitz in der Regierung).
In der EU müssen Sie eine Datenschutzerklärung haben, die Benutzer über die
beschissenen Dinge informiert, die Sie mit ihren Daten machen. Sie haben das Recht,
vergessen zu werden und Ihre Daten herunterzuladen (einschließlich, aber nicht
beschränkt auf Moderation und interne Kommentare zu Ihrer Person).
## Wandel des Umfangs, überall
Software muss zuverlässig, ständig aktualisiert, immer weiterentwickelt sein,
niemals ausfallen und trotzdem einigermaßen erschwinglich bleiben.
Das bedeutet Software basierend auf Datenbanken mit einem Dateisystem, das in drei
verschiedenen Rechenzentren läuft, Logging, Observability, End-to-End-Testing und
Live-Migrationen.
Software muss nicht nur für eine bestimmte Zielgruppe funktionieren, Software muss
für alle und alles zwischen 0 und mindestens 100 Jahren (Ihre Oma und die Kinder,
die dieses TikTok-Ding benutzen) entwickelt werden. Sie muss auf Apple-Computern,
Windows ARM und x86-64, Linux, Smartphones und vielleicht auf einem Fernseher funktionieren.
Farbpaletten können nicht zufällig sein, weil manche Menschen möglicherweise nicht
zwischen verschiedenen Farben unterscheiden können. Deine Software muss anzeigen,
sprechen und [braille](https://en.wikipedia.org/wiki/Braille) können.
Software hat fast keine Grenzen und kann überall eingesetzt werden.
Software muss alt werden können, wir sprechen von Jahrzehnten und bald und vielleicht
sogar jetzt einem halben Jahrhundert.
## Schlusswort
Zusammenfassend ist Software zu einem großen Teil der realen Welt geworden und muss
viel mehr reale Dinge tun und mit ihnen umgehen.
Natürlich sollte ein Blog wahrscheinlich nicht mit *Next.js* geschrieben werden.
---
# Go is a great scripting language
> Go is a great scripting language
**TL;DR:** Go is a great scripting language if you require more than a shell language.
*Published on 2025-05-11 · en · https://codefionn.eu/go-is-a-great-scripting-language/*
I recently had to write a Dockerfile generator for caching automatic testing
runs and incrementally caching the build without an actual incremental build in
CICD.
The job: turn project files into a Dockerfile whose layers CI can cache
Previously this generator was written in bash and powershell.
Required features for the choosen language were:
- easy xml/general file parsing without external packages
- not slow
- fast startup
- can be easily run with minimal effort
The following languages/runtimes were in the running for this task:
- Deno (TypeScript/ECMAScript runtime)
- Go
- Lua
- Nushell
- Python
Deno, Lua and Python require external packages for parsing xml files. Deno
would be easier, because external dependencies can simply be imported with just
an URL. Nushell has problems parsing certain xml files. Go on the other hand
has xml parsing builtin.
Go is also simple to run with `go run main.go`, doesn't require auxillary files
(like `packages.json` with npm), but can also be compiled and cached. Also, Go
is trivally multi-threaded, which is a big problem in many interpreted
languages.
---
# Go ist eine gute Skriptsprache
> Go ist eine gute Skriptsprache
**TL;DR:** Go ist eine gute Skriptsprache, wenn du mehr als eine Shell-Sprache benötigst.
*Veröffentlicht am 2025-05-11 · de · https://codefionn.eu/go-ist-eine-gute-skriptsprache/*
Ich musste kürzlich einen Dockerfile-Generator schreiben für das
Zwischenspeichern automatischer Test-Läufe und die inkrementelle
Zwischenspeicherung des Builds ohne einen tatsächlichen inkrementellen Build in
CICD.
Die Aufgabe: aus Projektdateien ein Dockerfile mit zwischenspeicherbaren Schichten
Zuvor war dieser Generator in Bash und PowerShell geschrieben.
Benötigte Features für die gewählte Sprache waren:
- einfaches XML/allgemeines Datei-Parsing ohne externe Pakete
- nicht langsam
- schneller Start
- kann einfach mit minimalem Aufwand ausgeführt werden
Die folgenden Sprachen/Laufzeiten standen für diese Aufgabe zur Auswahl:
- Deno (TypeScript/ECMAScript-Runtime)
- Go
- Lua
- Nushell
- Python
Deno, Lua und Python benötigen externe Pakete für das Parsen von XML-Dateien.
Deno wäre einfacher, weil externe Abhängigkeiten einfach mit nur einer URL
importiert werden können. Nushell hat Probleme beim Parsen bestimmter
XML-Dateien. Go hingegen hat XML-Parsing eingebaut.
Go ist auch einfach mit `go run main.go` ausführbar, benötigt keine Hilfsdateien
(wie `packages.json` bei npm), kann aber auch kompiliert und zwischengespeichert
werden. Außerdem ist Go trivial multi-threaded, was ein großes Problem in vielen
interpretierten Sprachen ist.
---
# Rust Buildkit CICD Pipeline
> A basic rust buildkit CICD pipeline with cross platform compilation
*Published on 2025-02-26 · en · https://codefionn.eu/rust-builkit-cicd-pipeline/*
The following files create an buildkit CICD pipeline with cross platform
compilation support for `x86-64`, `aarch64` and `riscv64gc` for *Rust*. Also,
the program is compiled with *musl*, so the resulting image is as small as
possible.
The tests output cobertura files (via `cargo-tarpaulin`) for use in your
git-platform (e.g. Gitlab).
Also, this whole pipeline has been run with *podman* in the background with
*docker-buildx* installed but using the *podman* context, so it can be run
without root privileges.
You will have to modify the pipeline further to fit your program and upload the
resulting docker images to a registry.
Run the whole pipeline with:
```sh
docker buildx bake default lint clippy test
```
Your `docker-bake.hcl`-file:
```hcl
target "default" {
platforms = [
"linux/amd64",
"linux/arm64",
"linux/riscv64",
]
output = ["type=cacheonly"]
}
target "lint" {
target = "lint"
output = ["type=cacheonly"]
}
target "clippy" {
target = "clippy"
output = ["type=cacheonly"]
}
target "test" {
target = "test-results"
output = [
"type=local,dest=.",
]
}
```
Your `Dockerfile`:
```Dockerfile
# syntax=docker/dockerfile:1
# Script for converting Go's TARGETPLATFORM to Rust's target triple
# (also comes with RUSTFLAGS settings)
FROM --platform=${BUILDPLATFORM} docker.io/python:3.14-rc-alpine AS build-env
ARG TARGETPLATFORM
RUN < ./src/main.rs
COPY Cargo.toml Cargo.lock ./
FROM toml-files AS fetch
RUN . /env; cargo fetch --locked --target "$RUST_TARGET"
# Copy all source files to the container now
FROM fetch AS fetch-with-files
COPY . .
FROM fetch-with-files AS clippy
RUN cargo clippy --all-targets --all-features -- -D warnings
FROM fetch-with-files AS lint
RUN cargo fmt --check
FROM fetch-with-files AS test
RUN cargo-tarpaulin --engine llvm --out Html --out Xml --output-dir /target/coverage
FROM scratch AS test-results
COPY --from=test /target/coverage/ /target/coverage/
FROM fetch-with-files AS build
ARG TARGETPLATFORM
RUN --mount=type=cache,id=cargo-build-${TARGETPLATFORM},dst=/src/target . /env; cargo build --release --target $RUST_TARGET
RUN --mount=type=cache,id=cargo-build-${TARGETPLATFORM},dst=/src/target . /env; mkdir /app; cp -r ./target/$RUST_TARGET/release/* /app
RUN ls
FROM scratch AS final
COPY --from=build /app/ /app/
CMD ["/app/my-app"]
```
Your `.dockerignore`:
```gitignore
/.git
/.gitignore
/target
**/target
/docker-backe.hcl
/Dockerfile
/.vscode
/docs
/README.md
```
---
# Useful git stuff
> Useful commands for using git
*Published on 2024-12-14 · en · https://codefionn.eu/useful-git-stuff/*
**git** has a vast feature set for those, that want to clean up their merge
requests (before and after the review, but not during).
First of: Use the command line tool. For merging other tools may be more
useful, but please don't use anything more than that. 3rd party integrations
are always different, learn the CLI once and be good at git forever.
## List of useful commands
The list below is a list of useful, advanced git commands (so no just `git commit -a -m "msg"`)
| Command | Explanation |
|:---------------------------------------|:-------------------------------------------------------|
| git commit --amend | Change the last commit (be sure you can change it on |
| | the remote! |
| git rebase --interactive <ref>~ | With this you can fixup your commit structure from |
| | the COMMIT-REF to the latest commit on the branch |
| git reset --soft <ref> | Remove all commits up to but not including <ref> |
| | and add modified files in staging |
| git commit --fix <ref> | Create a simple commit fixing something in a merge |
| | request, so you can simply rebase it away in the |
| | future! |
| git add --patch <file> | Add only partial changes from a file |
## Things you should do
### git rerere
Did you ever get annoyed by rebasing onto the main branch and having to resolve
conflicts, which you have previously resolved?
Enter [**git rerere**](https://git-scm.com/book/en/v2/Git-Tools-Rerere), the
solution to your `git rebase` problems.
---
# Nützliche Git-Befehle
> Nützliche Befehle für die Verwendung von Git
*Veröffentlicht am 2024-12-14 · de · https://codefionn.eu/nuetzliche-git-befehle/*
**git** hat einen großen Funktionsumfang für diejenigen, die ihre Merge
Requests aufräumen wollen (vor und nach dem Review, aber nicht währenddessen).
Vorerst: Benutze das Kommandozeilen-Tool. Zum Mergen mögen andere Tools
nützlicher sein, aber bitte benutze nicht mehr als das. Integrationen von
Drittanbietern sind immer unterschiedlich, lerne die CLI einmal und sei für
immer gut in Git.
## Liste nützlicher Befehle
Die folgende Liste ist eine Liste nützlicher, fortgeschrittener Git-Befehle
(also nicht nur `git commit -a -m "msg"`)
| Befehl | Erklärung |
|:---------------------------------------|:-------------------------------------------------------|
| git commit --amend | Ändere den letzten Commit (sei sicher, dass du ihn auf |
| | dem Remote ändern kannst! |
| git rebase --interactive <ref>~ | Damit kannst du deine Commit-Struktur vom COMMIT-REF |
| | bis zum neuesten Commit auf dem Branch korrigieren |
| git reset --soft <ref> | Entferne alle Commits bis ausschließlich <ref> |
| | und füge geänderte Dateien zum Staging-Bereich hinzu |
| git commit --fixup <ref> | Erstelle einen einfachen Commit, der etwas in einem |
| | Merge Request korrigiert, sodass du ihn in Zukunft |
| | einfach wegrebasen kannst! |
| git add --patch <file> | Füge nur teilweise Änderungen aus einer Datei hinzu |
## Dinge, die du tun solltest
### git rerere
Hast du dich jemals darüber geärgert, auf den Main-Branch zu rebasen und
Konflikte lösen zu müssen, die du bereits zuvor gelöst hast?
Hier kommt [**git rerere**](https://git-scm.com/book/de/v2/Git-Tools-Rerere),
die Lösung für deine `git rebase`-Probleme.
---
# The PL series - In defense of dynamic type systems
> The programming language series - In partial defense of dynamic type systems
*Published on 2024-06-22 · en · https://codefionn.eu/the-pl-series-in-defense-of-dynamic-typesystems/*
This is the programming language series on this blog. This series of blog
articles is trying to explain certain programming language design
decisions/paradigms.
This article is about dynamic type systems and why they are a valid paradigm
for certain applications.
## First of: What is a dynamic type system?
Programming language like **ECMAScript** or
**Python** famously don't use explicit types, but also shells like
**(ba)sh** or **PowerShell**.
In dynamically type systems you do not have the specify the type of objects and
type checking is performed at runtime (e.g. primitive types). This typically
allows you to freely modifiy structures used, like adding properties or
functions.
## Consequences
The goal of dynamic type systems is to allow the programmer to the create
programs without thinking about (your own) types (at least that should be the
goal here). But types still have to be checked, if you call functions
manipulating lists or strings.
This means that programming languages using a dynamic type system, typically
also feature a heavy use of implicit type coercion (implicitly converting
types). E.g. in ECMAScript you have `==`, which
implicitly converts types and `===` which only checks equality of objects with
the same type or `"" + 0` is evaluated to just `"0"`.
Implicit coercion in Node.js: == converts, === doesn't
Also, a programmer has to write more tests, because the structure (objects,
function signatures) has to be tested as well.
Due to types being unknown before actually running a program here, programming
languages using this type system are typically interpreted or have a compiler
producing comparably slower programs or target a
VM.
Another consequence is that, it is harder to offer code completions because the
code editor/LSP has to look into function bodies quite extensivly to guess the
valid usage of a variable.
Refactorings are also made harder, because you can't just statically type check
your whole program for errors, because of the change. The programmer has to
creatively employ the use of regex to search and destroy (replace) or waste
countless hours using inferior search methods (not counting awk).
## Advantages
Dynamic type systems allow a programming language to be, well, more dynamic.
This allows you to:
- retroactively fix mistakes in a console interpreter
- sometimes fix the standard library (or [break it](https://github.com/mootools/mootools-core/issues/2402))
- polyfilling
- not needing to express complex structural behaviour in types (but in documentation).
## My opion
I prefer using statically typed languages for larger projects. But for very
small programs and shell-like senarios, I prefer the dynamic nature of dynamic
type systems.
Especially the relatively poor LSP experience and refactoring hell using
dynamically typed programming languages make them unsuited for larger systems.
As a PHP programmer sometimes handling older PHP code, I know.
Also: When using JSDoc with ECMAScript, you partially don't use a dynamic type
system anymore.
---
# Your language can improve correctness
> Your programming language of choice can actually improve the correctness of your program
*Published on 2024-04-10 · en · https://codefionn.eu/your-programming-language-can-improve-correctness/*
*A/N:* Unlike other articles on this blog, it isn't continuously updated.
Because this is a matter of opinion.
Yes, you read right: the programming language of your choice can actually
improve the correctness of your program. Not everything you choose is made
equal. Tooling choices actually matter.
## Example
Imagine two programs written in programming language A and another written in B:
- A is a statically typed programming language
(simplified example: `let x: int = 0`)
- B is a dynamically typed programming language, i.e. no types
(simplified example: `let x = 0`)
Both programming languages have the following equal conditions:
- Latency to executing the program (e.g. compilation step, startup of the interpreter)
- Runtime speed
- Automated testing
And no, this is not an article against dynamically typed programming languages.
### How do you improve correctness?
First of, correctness in this context means the following:
- your program does fullfill perceived (by the developer) initial requirements
- your program works in real-world deployments
For program written in **A** you can do the following:
1. Let others critique your code
2. Write automated tests
3. Do tests by hand
4. Use the forced upon you type system
For program written in **B** you can do the following:
1. Do the above 1-3
Same checks, minus one layer
The frequency of automated tests and manual tests can be improved with a smaller
latency to executing the program and faster runtime performance, which
most likely leads to increased program correctness.
There's also a trade-off between a more strict type system and a vastly
improved testing story.
### Comparision
Programming language **A** does provide a mechanism to improve the correctness
of your code: a static type system. **B** doesn't have that advantage and
looses on that point. Due to all other features being equal, **A** is better at
improving program correctness, because **B** cannot easily replace the need for
better correctness with more tests.
Of course, if it's too time-consuming for you to use said statically typed
language due to skill issues or comfort, you may be better off programming in
**B**.
## In practice Go vs. TypeScript
First of, a collection of features in both languages, that could drive correctness.
Summarizing **Go**:
- A static type system
- Fast compilation speed, even faster startup time of compiled programs
- [Built-in support for writing unit tests](https://go.dev/doc/tutorial/add-a-test)
Summarizing **TypeScript**:
- A static type system
- No built-in support for writing unit tests
- [Hot module replacement](https://v2.vitejs.dev/guide/features.html#hot-module-replacement) (in some cases)
**Go**'s type system is superior in correctness, because **TypeScript's** `any`
can at any time break your beautifully (painfully) typed world.
Due to **Go**'s built-in unit tests, small applications can more easily
be tested.
In small projects, **Go**'s compilation speed and amazing runtime speed,
increases the frequency of automated and manual tests, which is less likely with
**TypeScript**.
On the other hand in bigger web dev projects, I would rate both languages
equal, though my experience is lacking in this area (professional PHP, C#,
ECMAScript, small-time TypeScript programmer here).
Other bigger **TypeScript** applications cannot profit as much from the likes
of HMR, meaning you're better of
writing them in **Go**, notwithstanding other trade-offs.
Use the right to tool for the **job**. Not the DX tool. (DX as in = the thing
you are already the most comfortable with, before you used it). When you're not
on the job, maybe this just helps you to explain some of your tooling problems.
### Closing words
It was a hard decision to include
HMR to '**TypeScript's** features',
but it offsets compile time in (complicated) web dev environments. I didn't add
testing frameworks, because simple console applications can't really use a
built-in language feature for testing.
This article btw. only cares about language features, which (may) improve
program correctness.
This article was written with the help of Lume, a 11ty-like Deno static webpage
generator, and yes some TypeScript.
---
# DDNS with unbound and kea
> Dynamic DNS with unbound and kea for giving local devices DNS-names
*Published on 2023-11-14 · en · https://codefionn.eu/ddns-with-unbound/*
My [NixOS router](/nixos-router-with-j4125-and-intel-i225/) uses
[unboud](https://nlnetlabs.nl/projects/unbound/about/) as a DNS server and
[kea](https://www.isc.org/kea/) as the DHCPv4/6 server (currently the IPv6 DHCP
isn't working). This article contains a script for listening to changes in
*kea* DHCP-leases and writing the hostnames to unbound. This gives your local
devices domain names.
You might know that, *kea* also supports
DDNS configuration. While that may be true,
this only works, if the DNS server supports TSIG. The problem is that unbound
doesn't support it. I looked into moving from unbound to a differnt DNS
server (like *Bind9* or *Knot DNS*), but those are complicated to configure with
NixOS, so I stayed with unbound.
The solution: a bash script running as systemd service. The script itself
requires that unbound can be remote controlled and the *inotify-tools* for
listening to file changes.
```bash
#!/usr/bin/env bash
HOSTNAME="$(hostname).lan"
function readFile() {
if [[ "$2" == "A" ]] ; then
cat "$1" | tail -n +2 | while IFS=, read -r address hwaddr client_id valid_lifetime expire subnet_id fqdn_fwd fqdn_rev hostname state user_context
do
echo "${address},${hostname}"
done
else
cat "$1" | tail -n +2 | while IFS=, read -r address duid valid_lifetime expire subnet_id pref_lifetime lease_type iaid prefix_len fqdn_fwd fqdn_rev hostname hwaddr state user_context hwtype hwaddr_source
do
echo "${address},${hostname}"
done
fi
}
function readFileUnique() {
readFile "$1" $2 | uniq | while IFS=, read -r address hostname
do
if [[ "${hostname}" == *.$HOSTNAME ]] ; then
echo ${hostname} $2 ${address}
unbound-control local_data ${hostname} $2 ${address}
if [[ "$2" == "A" ]] ; then
echo ${address} | while IFS=. read -r ip0 ip1 ip2 ip3
do
unbound-control local_data ${ip3}.${ip2}.${ip1}.${ip0}.ip4.arpa. PTR ${hostname}
unbound-control local_data ${ip3}.${ip2}.${ip1}.${ip0}.in-addr.arpa. PTR ${hostname}
done
fi
fi
done
}
function syncFile() {
readFileUnique "$1" "$2"
while inotifywait -e close_write,create "$1" ; do
readFileUnique "$1" "$2"
done
}
syncFile "/var/lib/kea/dhcp4.leases" A &
syncFile "/var/lib/kea/dhcp6.leases" AAAA &
wait
```
This scripts reads the DHCP4/6-Leases CSV database stored by *kea* and then
reads the address and hostname from that table. *unbound-control* is called to
set the `A` or `AAAA` record. If it is IPv4, we reverse the IP-address and store
a PTR record for reverse IP-lookup (`dig -x YOUR.IP.GOES.HERE`). The wait at
the end waits for the to forked `syncFile`-functions to finish.
This script first reads all DHCP-leases and sets the DNS records accordingly
and then waits for changes in the DHCP-leases with inotify.
Hostnames used for creating these DNS-Records must end here with your
hostname + local-domain, That's why, you have to make sure that your kea DHCPv4/6 has
the following configuration option:
```
ddns-qualifying-suffix = "YOUR-HOSTNAME.lan"
```
In your systemd-Service set `PartOf`, `After` and `Wants` to `unbound.service`.
This will ensure that, the script is started, after `unbound` and that the
script is always restarted, when unbound itself is. `WantedBy` must be set to
`multi-user.target`.
The configuration in NixOS is:
```nix
systemd.services.unbound-sync = {
enable = true;
path = with pkgs; [ unbound inotify-tools ];
script = ''
function readFile() {
if [[ "''\$2" == "A" ]] ; then
cat "''\$1" | tail -n +2 | while IFS=, read -r address hwaddr client_id valid_lifetime expire subnet_id fqdn_fwd fqdn_rev hostname state user_context
do
echo "''\${address},''\${hostname}"
done
else
cat "''\$1" | tail -n +2 | while IFS=, read -r address duid valid_lifetime expire subnet_id pref_lifetime lease_type iaid prefix_len fqdn_fwd fqdn_rev hostname hwaddr state user_context hwtype hwaddr_source
do
echo "''\${address},''\${hostname}"
done
fi
}
function readFileUnique() {
readFile "''\$1" ''\$2 | uniq | while IFS=, read -r address hostname
do
if [[ "''\${hostname}" == *.${config.networking.hostName}.lan ]] ; then
echo ''\${hostname} ''\$2 ''\${address}
unbound-control local_data ''\${hostname} ''\$2 ''\${address}
if [[ "''\$2" == "A" ]] ; then
echo ''\${address} | while IFS=. read -r ip0 ip1 ip2 ip3
do
unbound-control local_data ''\${ip3}.''\${ip2}.''\${ip1}.''\${ip0}.ip4.arpa. PTR ''\${hostname}
unbound-control local_data ''\${ip3}.''\${ip2}.''\${ip1}.''\${ip0}.in-addr.arpa. PTR ''\${hostname}
done
fi
fi
done
}
function syncFile() {
readFileUnique "''\$1" "''\$2"
while inotifywait -e close_write,create "''\$1" ; do
readFileUnique "''\$1" "''\$2"
done
}
syncFile "/var/lib/kea/dhcp4.leases" A &
syncFile "/var/lib/kea/dhcp6.leases" AAAA &
wait
'';
wants = [ "network-online.target" "unbound.service" ];
after = [ "network-online.target" "unbound.service" ];
partOf = [ "unbound.service" ];
wantedBy = [ "multi-user.target" ];
};
```
---
# Some of PHP's problems
> Some of PHP's problems that lead to technical difficulties
*Published on 2023-11-12 · en · https://codefionn.eu/some-of-phps-problems/*
First of: What even is PHP?
PHP is a widely used programming language in the Web. Wordpress & plugins are
built on PHP. Another cool thing about PHP is, that can just throw a PHP script
onto a typical webserver and it will *just work*.
The language's type system itself is a mix between ECMAScript, TypeScript and
Java.
[PHP 8.2 even deprecated dynamic properties](https://www.php.net/manual/en/migration82.deprecated.php)
(though you can still opt-in on a class by class basis). It has a package
manager called [composer](https://getcomposer.org/) and the package registry is
[packagist](https://packagist.org/).