Das Doku-Paradox: Warum Teams dokumentieren, wenn es zu spät ist — und wie man es früher schafft

Jeder kennt die Situation: Ein kritischer Dienst fällt aus. Das Telefonj läuft heiß. Der Slack-Kanal brennt. Und irgendjemand — meist der neue Kollege, der drei Wochen im Haus ist — fragt: „Gibt’s dazu eine Doku?“

Stille.

Dann, nach einer halben Stunde Suchen, findet jemand ein Confluence-Dokument, das zuletzt 2021 aktualisiert wurde. Die Servernamen stimmen nicht mehr. Die Ports sind falsch. Der beschriebene Workaround funktioniert längst nicht mehr, weil zwischenzeitlich ein Major-Upgrade stattfand, das niemand dokumentiert hat.

Und jetzt — jetzt, mitten im Ausfall, unter Zeitdruck, mit Management, das alle fünf Minuten nach dem Status fragt — jetzt soll Dokumentation entstehen. Gute Dokumentation. Vollständig. Nachvollziehbar.

Das ist das Doku-Paradox: Dokumentation ist genau dann am wichtigsten, wenn sie am schwersten zu erstellen ist.

Die drei Zustände von Dokumentation

Dokumentation existiert in genau drei Zuständen. Und jeder ist schlimmer als der vorherige.

Zustand 1: Gar nicht

Kein Wiki-Eintrag. Kein README. Nichts im Git-Repo. Die Konfiguration existiert nur auf dem Server und im Kopf der Person, die sie aufgesetzt hat.

Das ist offensichtlich schlecht. Aber — und das wird oft übersehen — es hat einen Vorteil: Es ist ehrlich. Jeder, der ankommt, weiß sofort: Hier gibt es keine Doku. Ich muss fragen. Ich muss vorsichtig sein. Ich muss mich auf nichts verlassen, was ich finde.

Das ist unangenehm, aber klar.

Zustand 2: Veraltet

Jemand hat 2021 eine schöne Doku geschrieben. Architekturdiagramme. Schritt-für-Schritt-Anleitungen. Tabellen mit Servernamen und IPs. Richtig gute Arbeit.

Aber jetzt ist es 2026. Fünf Server aus der Doku existieren nicht mehr. Drei neue sind dazugekommen. Der Load Balancer wurde durch einen anderen ersetzt. Die SSL-Zertifikate rotieren mittlerweile automatisch, aber die Doku beschreibt noch den manuellen Prozess.

Veraltete Doku ist gefährlicher als keine Doku. Warum? Weil sie Vertrauen erweckt, das nicht gerechtfertigt ist. Du liest das Dokument, denkst „Alles klar, ich verstehe das System“ — und handelst auf Basis von Informationen, die schlicht falsch sind.

Beim Zustand „gar nicht“ fragst du nach. Beim Zustand „veraltet“ glaubst du, du müsstest nicht fragen.

Zustand 3: Falsch

Das ist die Eskalation von Zustand 2. Veraltete Doku könnte noch stimmen. Falsche Doku stimmt aktiv nicht — und sieht dabei aus, als würde sie stimmen.

Falsche Doku ist das Ergebnis von „ich hab das schnell angepasst, das stimmt so“ — wenn es nicht stimmt. Von copy-paste aus einer anderen Doku, bei der ein Detail übersehen wurde. Von jemandem, der schreibt, wie etwas funktionieren sollte, nicht wie es funktioniert.

Falsche Doku ist aktiv schädlich. Sie führt zu Fehlern, die ohne die Doku nicht passiert wären. Sie ist eine Zeitbombe.

Die bittere Erkenntnis: Der Weg von „keine Doku“ zu „falsche Doku“ ist kürzer als man denkt. Ein halbgutes Update eines alten Dokuments reicht.

Warum niemand dokumentiert

Die Gründe sind banal und universell.

Kein unmittelbarer Nutzen. Wenn du eine Konfiguration änderst, hast du einen sofortigen Effekt: Der Dienst funktioniert wieder. Die Pipeline läuft. Der Bug ist weg. Wenn du dieselbe Änderung dokumentierst, passiert — nichts. Zumindest nichts, das du spürst. Der Nutzen ist latent, diffus, irgendwann in der Zukunft.

Kein Deadline-Druck. Features haben Deadlines. Bugs haben SLAs. Security-Patches haben CVE-Nummern und verantwortliche Offenlegungszeitpläne. Dokumentation hat nichts davon. Niemand ruft am Freitag um 17 Uhr an und sagt „Die Doku für den neuen Mailserver muss bis Montag fertig sein.“

„Das weiß ich doch im Kopf.“ Das ist der gefährlichste Grund, weil er wahr ist — im Moment. Du hast das System aufgesetzt. Du kennst jeden Knopf, jeden Workaround, jeden historischen Grund, warum das so ist und nicht anders. Warum solltest du aufschreiben, was du ohnehin weißt? Das wäre redundant. Ineffizient.

Bis du kündigst. Krank wirst. Urlaub machst. Oder — und das passiert öfter als man denkt — bis du es vergisst. Drei Monate später, unter Stress, um 2 Uhr nachts, erinnerst du dich nicht mehr, warum der DNS-Resolver auf genau diesem Host auf Port 5353 lauscht. Oder ob das noch gebraucht wird. Oder ob das ein temporärer Hack war, der längst weg sollte.

Und dann machst du genau das, was man nicht machen sollte: Du lässt es stehen, weil du dir nicht sicher bist, ob etwas davon abhängt.

Die Kosten der fehlenden Doku

Die Kosten sind massiv, aber sie fallen selten dem zu, der die Doku nicht geschrieben hat. Sie externalisieren sich — auf Kollegen, auf Nachfolger, auf das Projekt.

Onboarding-Zeiten

Ein neuer Kollege braucht bei guter Dokumentation vielleicht zwei Wochen, um produktiv zu werden. Bei fehlender Doku sind es zwei Monate. In denen fragt er alles. In denen erfahrene Kollegen unterbrochen werden. In denen er Fehler macht, die ein Readme in fünf Minuten verhindert hätte.

Onboarding-Kosten sind die sichtbarste und messbarste Konsequenz. Und trotzdem wird in den seltensten Fällen der Dokumentationsmangel als Grund identifiziert. Es heißt dann „Der Einarbeitungsprozess muss optimiert werden“ — statt „Wir haben keine Doku“.

Single Points of Failure

Wenn eine Person die einzige ist, die ein System versteht, ist das ein Single Point of Failure. Nicht das System — die Person. Und Menschen sind deutlich anfälliger als gut administrierte FreeBSD-Server. Sie kündigen. Sie werden krank. Sie gewinnen im Lotto und ziehen nach Neuseeland.

Jedes System, das nur eine Person versteht, ist ein Risiko. Und dieses Risiko wird in den seltensten Fällen in der Risikoanalyse auftauchen, weil — ihr ahnt es — niemand dokumentiert hat, dass das System nur von einer Person verstanden wird.

Update-Angst

„Wir können nicht updaten, wir wissen nicht, ob das noch funktioniert.“ Das ist der Satz, der jeden Admin das Fürchten lehrt. Weil irgendjemand vor drei Jahren einen Patch auf einem System eingespielt hat, der einen Edge Case abdeckt, der nirgends dokumentiert ist. Und jetzt soll ein Major-Upgrade gemacht werden, und niemand weiß, ob dieser Patch noch relevant ist, ob er noch gebraucht wird, oder ob er längst in den Upstream geflossen ist.

Also bleibt das System auf einer alten Version. Aus Angst. Und aus mangelndem Vertrauen in die eigene Dokumentation, die nicht existiert.

Dienstleister-Konflikte

„Mein Teil funktioniert.“ — Der Klassiker bei verteilten Systemen mit externen Dienstleistern. Die Datenbank-Admins sagen „Die DB läuft“. Die App-Entwickler sagen „Die App läuft“. Die Netzwerk-Admins sagen „Das Netzwerk läuft“. Und trotzdem funktioniert das Gesamtsystem nicht.

Jeder kennt nur seinen Teil. Niemand kennt die Schnittstellen. Niemand hat dokumentiert, wie die Teile zusammenhängen. Und jetzt sitzen alle im Kriegsrat und zeigen mit dem Finger aufeinander.

Gute Dokumentation der Schnittstellen — der Verträge zwischen den Systemen, nicht der Systeme selbst — hätte das verhindert. Aber Schnittstellen zu dokumentieren ist noch unwirtschafter als Systeme zu dokumentieren, weil es keinen klaren Eigentümer gibt.

Praktische Lösungen

Genug der Diagnose. Hier ist die Therapie.

Living Documentation: Doku als Code

Der beste Zustand von Dokumentation ist der, in dem sie nicht gepflegt werden muss, weil sie sich selbst pflegt. Living Documentation bedeutet: Die Dokumentation ist nicht ein separates Dokument, das man aktualisieren muss. Sie ist Teil des Codes, der ohnehin gepflegt wird.

Ansible-Playbooks als Dokumentation. Ein gut geschriebenes Ansible-Playbook ist die Dokumentation. Jede Task beschreibt, was auf dem System passiert. Die Variablen zeigen, welche Parameter verwendet werden. Die Handler zeigen, was bei Änderungen passiert. Wenn das Playbook aktuell ist, ist die Doku aktuell. Wenn nicht — dann läuft das Playbook auch nicht, und das Problem ist ein anderes.

Ein Beispiel:

# roles/mailserver/tasks/main.yml
# Postfix + Dovecot Mailserver Setup
# See: https://wiki.tgeppert.de/mailserver for architecture overview

- name: Install Postfix and Dovecot
  ansible.builtin.package:
    name:
      - postfix
      - dovecot
      - dovecot-pigeonhole
    state: present
  tags: [install, mail]

- name: Configure Postfix virtual domains
  ansible.builtin.template:
    src: postfix/virtual_domains.j2
    dest: /etc/postfix/virtual_domains
    owner: root
    group: wheel
    mode: '0644'
  notify: Reload Postfix
  tags: [config, mail]

Das Playbook sagt dir: Welche Pakete sind installiert? Welche Konfigurationsdateien gibt es? Welche Berechtigungen? Welche Tags für selektives Ausführen? Du musst kein separates Dokument pflegen — das Playbook ist das Dokument.

Terraform-Module als Architektur-Beschreibung. Dasselbe gilt für Terraform. Ein Terraform-Modul beschreibt die Infrastruktur deklarativ. Die Ressourcen, die Abhängigkeiten, die Variablen — das alles ist gleichzeitig Code und Dokumentation.

# modules/webapp/main.tf
# Web Application Stack: LB -> App -> DB
# Last reviewed: 2026-04

resource "proxmox_vm_qemu" "webapp" {
  name        = "webapp-${var.environment}"
  target_node = var.proxmox_node
  clone       = "freebsd-14-template"
  # ...
}

Wenn jemand die Architektur verstehen will, liest er das Terraform-Modul. Wenn etwas geändert wird, ändert sich das Modul. Die Doku aktualisiert sich von selbst — weil sie identisch mit dem Code ist.

ZFS-Snapshots als Änderungsprotokoll

Hier wird es interessant für die FreeBSD-Fraktion unter uns. ZFS hat eine Eigenschaft, die fast niemand für Dokumentation nutzt, die aber extrem wertvoll ist: Snapshots.

Jeder ZFS-Snapshot ist ein punktuelles Abbild des Dateisystems. Wenn du Snapshots regelmäßig erstellst — was du ohnehin tun solltest —, hast du eine chronologische Aufzeichnung jeder Änderung auf Dateisystemebene.

# Snapshot erstellen (z.B. vor einem Upgrade)
zfs snapshot zroot/usr/local@pre-upgrade-2026-04-23

# Was hat sich seit dem letzten Snapshot geändert?
zfs diff zroot/usr/local@daily-2026-04-22 zroot/usr/local@daily-2026-04-23

Die Ausgabe von zfs diff zeigt dir exakt, welche Dateien hinzugekommen, geändert oder gelöscht wurden. Das ist kein Ersatz für eine menschliche Dokumentation — aber es ist ein Änderungsprotokoll, das sich nicht vergessen werden kann. Es passiert automatisch.

Kombiniert mit einem Commit-Message-Stil für Snapshot-Namen (@pre-upgrade-2026-04-23, @post-dovecot-config), entsteht eine Art Git-Log auf Dateisystemebene. Ohne dass jemand ein Git-Log pflegen muss.

Die Documentation-First-Regel: Kein System ohne README im Repo

Hier ist eine einfache Regel, die den Charakter einer Organisationskultur verändert: Kein System geht live ohne ein README im zugehörigen Repository.

Nicht ein perfektes README. Nicht eine 20-seitige Architekturdokumentation. Ein README. Eine Seite. Was ist das? Wie starte ich es? Wo läuft es? Wen frag ich, wenn etwas kaputt ist?

# Mailserver (Postfix + Dovecot)

## Was ist das?
Zentrale Mail-Infrastruktur für @tgeppert.de und @beispiel.de

## Wo läuft es?
- Host: mx01.tgeppert.de (Proxmox VM, FreeBSD 14)
- IP: 192.168.1.50 (intern), 203.0.113.50 (extern)
- Ansible-Playbook: `ansible/mailserver.yml`

## Wie starte ich es?

bash
ansible-playbook ansible/mailserver.yml –tags install,config

## Wen frag ich?
Thorsten Geppert (thorsten@tgeppert.de)

## Bekannte Probleme
- DKIM-Signaturen müssen nach Cert-Rotation manuell geprüft werden
- Siehe Issue #42

Das ist keine Rocket Science. Das ist fünf Minuten Arbeit. Und es ist mehr Dokumentation, als 90% der Systeme in 90% der Unternehmen haben.

Die Regel ist einfach: Kein Deployment ohne README. Keine Ausnahmen. Wenn das README fehlt, geht der Pull Request nicht durch. Punkt.

Warum FreeBSDs Manpage-Kultur ein Vorbild ist

FreeBSD macht etwas richtig, das viele Linux-Distributionen vernachlässigen: Die Manpages sind erstklassig.

Wenn du auf einem FreeBSD-System man rc.conf eingibst, bekommst du eine detaillierte, aktuelle, durchsuchbare Dokumentation aller verfügbaren Systemparameter. Mit Beispielen. Mit Defaults. Mit Querverweisen. Und — das ist der entscheidende Punkt — die Manpages werden zusammen mit dem Code gepflegt. Sie sind Teil des gleichen Repositories, desselben Release-Prozesses, derselben Review-Kultur.

Das funktioniert, weil in der FreeBSD-Community die Erwartung besteht: Wenn du ein Feature einreichst, kommt die Doku mit. Ein Patch ohne Manpage-Update wird nicht gemerged. Nicht als Strafe, sondern weil Dokumentation als Teil des Features verstanden wird — nicht als Nachgang.

Diese Kultur lässt sich nicht über Nacht einführen. Aber das Prinzip lässt sich übertragen: Doku und Code gehören in denselben Review-Prozess. Wenn der Pull Request das Feature bringt, muss er auch die Doku bringen. Sonst kein Merge.

Git-Repositories für Konfigurationen

Die Idee ist simpel, aber die Umsetzung hat weitreichende Konsequenzen: Jede Konfiguration, die auf einem Server lebt, gehört in ein Git-Repository.

Nicht nur der Anwendungscode. Die nginx-Konfiguration. Die pf-Regeln. Die cron-Jobs. Die /etc/rc.conf. Alles.

Warum?

  1. Versionierung. Du kannst sehen, was sich wann geändert hat. Und — wichtiger noch — du kannst zurückrollen. git log /etc/nginx/sites-available/example.conf zeigt dir die Geschichte. git diff HEAD~1 zeigt dir die letzte Änderung. Das ist Dokumentation, die sich selbst schreibt.
  2. Verteilung. Mit Ansible, Puppet oder einfach git pull verteilst du Konfigurationen konsistent. Kein „auf Server A ist die alte Version, auf Server B die neue“.
  3. Review. Änderungen an der Konfiguration können wie Code-Änderungen behandelt werden: Pull Request, Review, Merge. Plötzlich hat jede Änderung einen Kontext — wer, wann, warum.
  4. Automatische Dokumentation. Die Commit-Historie ist das Änderungsprotokoll. Kein Mensch muss ein Change-Log pflegen. Git macht es.
# /etc in ein Git-Repo verwandeln (FreeBSD)
cd /etc
git init
git add rc.conf pf.conf nginx/ postfix/
git commit -m "Initial commit: current server configuration"

# Änderung tracken
git add rc.conf
git commit -m "Enable moused on /dev/ums0 for USB mouse support"

Das ist kein Ersatz für eine Architekturdokumentation. Aber es ist ein Fundament, auf dem man aufbauen kann. Und es kostet fast nichts.

Automatische Doku durch Monitoring und Logging

Die letzte Säule: Monitoring und Logging als automatische Dokumentation.

Monitoring-Systeme wie Prometheus, Grafana, Icinga oder Zabbix erfassen permanent den Zustand deiner Systeme. Das ist nicht nur operativ wertvoll — es ist auch Dokumentation.

  • Grafana-Dashboards zeigen die aktuelle Architektur. Welche Dienste laufen? Welche Metriken werden erfasst? Welche Schwellwerte gelten? Ein gut gebautes Dashboard ist eine visuelle Dokumentation des Systems.
  • Alert-Regeln dokumentieren, was als problematisch gilt. Wenn der Alert „Mailqueue > 500″ existiert, ist das eine Aussage: Eine Mailqueue über 500 Nachrichten ist nicht normal. Das ist Dokumentation.
  • Log-Aggregation (mit Loki, Elastic oder einfach syslog) zeigt, was passiert ist. Die Logs sind das Tagebuch des Systems — automatisch, unausweichlich, nicht vergesslich.

Die Idee: Nicht alles muss von Hand geschrieben werden. Monitoring und Logging produzieren kontinuierlich Dokumentation. Die Kunst besteht darin, diese Daten so aufzubereiten, dass sie auch als Dokumentation verständlich sind — und nicht nur als Rohdaten.

Das 5-Minuten-Prinzip

Alle Strategien oben helfen, aber sie lösen nicht das grundlegende Problem: den Moment, in dem du etwas reparierst und denkst „Das muss ich nicht aufschreiben, das ist nur ein Quick-Fix.“

Hier kommt das 5-Minuten-Prinzip: Wenn du etwas reparierst, nimm dir fünf Minuten Zeit und schreib auf, was das Problem war.

Nicht „ausführlich dokumentieren“. Nicht „ein Confluence-Dokument erstellen“. Fünf Minuten. In dein Notizbuch, in ein README.md im Repo, in den Commit-Message-Body, in den Slack-Kanal — irgendwohin.

## 2026-04-23: Mailqueue stauete sich

**Problem:** Mailqueue auf mx01 lief über, weil Dovecot-AUTH-Timeout auf 10s stand.
**Lösung:** Timeout auf 30s erhöht. Siehe commit abc123.
**Ursache:** Nach dem Update auf Dovecot 2.4 ist der Default-Timeout gesunken.
**Follow-up:** Prüfen, ob 30s ausreichen oder ob wir die Connection-Pooling-Logik anpassen müssen.

Das ist keine perfekte Dokumentation. Aber es ist eine Dokumentation. Und sie ist unendlich viel besser als die Alternative: drei Monate später dasselbe Problem, dieselbe Sucherei, derselbe Aufwand.

Das 5-Minuten-Prinzip funktioniert, weil es den inneren Schweinehund umgeht. „Fünf Minuten“ ist kein „ich muss erst ein Dokument erstellen“. Es ist eine kurze, machbare Investition. Die Hürde ist niedrig genug, dass sie im Alltag überwindbar ist. Und der Effekt kumuliert: Nach einem Jahr hast du eine Sammlung von Problembeschreibungen und Lösungen, die wertvoller ist als jedes Architektur-Wiki.

Das eigentliche Problem

Das Doku-Paradox ist kein Technologie-Problem. Es ist ein Kultur-Problem.

Dokumentation wird als Nachgang behandelt. Als „das, was man macht, wenn die eigentliche Arbeit fertig ist“. Als das, was bei Zeitdruck zuerst gestrichen wird. Als das, was keine Deadline hat und deshalb nie fertig wird.

Aber Dokumentation ist kein Nachgang. Dokumentation ist Teil des Systems.

Ein System ohne Dokumentation ist wie ein Programm ohne Tests. Es mag jetzt funktionieren. Aber du kannst nicht verifizieren, dass es funktioniert. Du kannst es nicht sicher ändern. Du kannst es nicht weitergeben. Es ist fragil.

Die drei Zustände von Dokumentation — gar nicht, veraltet, falsch — sind keine Stadien eines Prozesses. Sie sind Symptome einer Kultur, die Dokumentation als optional betrachtet.

Die Lösungen — Living Documentation, Git-Repositories für Konfigurationen, ZFS-Snapshots, Manpage-Kultur, das 5-Minuten-Prinzip — haben eines gemeinsam: Sie machen Dokumentation nicht optional. Sie bauen sie in den Prozess ein. Sie machen es einfacher, Dokumentation zu erstellen, als sie wegzulassen.

Und das ist der Hebel. Nicht Appell. Nicht „wir sollten mehr dokumentieren“. Sondern Systeme und Prozesse, in denen Dokumentation der Weg des geringsten Widerstands ist.

TL;DR

  • Das Paradox: Doku ist am wichtigsten, wenn sie am schwersten zu erstellen ist. Unter Zeitdruck. Nach einem Ausfall. Wenn der Admin kündigt.
  • Drei Zustände: Gar nicht (ehrlich), veraltet (gefährlich), falsch (aktiv schädlich). Jeder ist schlimmer als der vorherige.
  • Warum nicht: Kein unmittelbarer Nutzen, kein Deadline-Druck, „Das weiß ich im Kopf.“
  • Die Kosten: Langes Onboarding, Single Points of Failure, Update-Angst, Dienstleister-Konflikte.
  • Lösungen: Doku als Code (Ansible, Terraform), ZFS-Snapshots als Change-Log, README-Pflicht, Manpage-Kultur, Git für Configs, Monitoring als automatische Doku.
  • 5-Minuten-Prinzip: Fünf Minuten aufschreiben, was das Problem war. Immer.
  • Dokumentation ist kein Nachgang. Sie ist Teil des Systems.

Infrastructure as Code: Warum Handarbeit auf Servern gefährlich ist

Jeder Systemadministrator kennt den Moment: Man meldet sich auf einem Server an, führt ein paar Befehle aus, ändert eine Konfigurationsdatei, installiert ein Paket. Alles funktioniert. Ein paar Wochen später steht man vor demselben Problem — nur auf einem anderen Server. Und man kann sich nicht mehr erinnern, welche Befehle man ausgeführt hat. Der Server ist ein Schneemann: Er sieht aus wie die anderen, aber unter der Oberfläche ist alles anders.

Infrastructure as Code (IaC) ist die Antwort auf dieses Problem. Und wer als Softwareentwickler und Administrator — wie ich — beide Welten kennt, weiß, dass IaC nicht nur ein Trend ist, sondern eine Notwendigkeit.

Das Problem mit manuellen Servern

Manuelle Administration skaliert nicht. Das ist keine Meinungsfrage, sondern Mathematik. Wenn jeder Server ein Unikat ist, dann ist jeder Server ein Risiko. Wenn ein Server ausfällt und niemand weiß, wie er konfiguriert war, dann ist der Wiederherstellungsprozess ein Glücksspiel.

Die typischen Symptome sind vertraut:

  • Konfigurationsdrift. Server, die identisch sein sollten, unterscheiden sich in subtilen — und manchmal kritischen — Details.
  • Wissensmonopole. Nur eine Person weiß, wie ein bestimmter Server konfiguriert ist. Wenn diese Person krank wird oder geht, ist das Wissen weg.
  • Nicht-reproduzierbare Zustände. Ein Server funktioniert, aber niemand kann erklären, warum. Oder schlimmer: Niemand kann ihn neu aufsetzen.
  • Angst vor Änderungen. Weil niemand weiß, was passieren wird, wenn man etwas ändert, ändert man nichts. Bis man es muss. Und dann ist es zu spät.

Was Infrastructure as Code bedeutet

IaC ist nicht einfach „Skripte schreiben“. Es ist ein Paradigmenwechsel in der Art und Weise, wie wir über Infrastruktur denken.

Deklarativ statt imperativ. Statt zu beschreiben wie ein Server konfiguriert werden soll („installiere nginx, kopiere die Konfiguration, starte den Dienst“), beschreibt man was der Zustand sein soll („nginx muss installiert sein, die Konfiguration muss diesen Inhalt haben, der Dienst muss laufen“). Der IaC-Workflow kümmert sich um das Wie.

Versioniert. Jede Änderung an der Infrastruktur ist in Git committet. Man kann sehen, wer was wann geändert hat. Man kann zu einem früheren Zustand zurückkehren. Man kann Änderungen über Code-Reviews prüfen lassen.

Reproduzierbar. Wenn ein Server ausfällt, kann er aus der IaC-Definition komplett neu aufgesetzt werden. Wenn ein neuer Server benötigt wird, kann er in Minuten statt Stunden erstellt werden.

Testbar. Bevor eine Änderung auf Produktion geht, kann sie in einer Testumgebung validiert werden. Syntaxfehler, fehlende Abhängigkeiten, inkompatible Konfigurationen — alles wird erkannt, bevor es Schaden anrichtet.

Die Werkzeuge

Die Wahl des Werkzeugs hängt vom Kontext ab. Hier eine Übersicht der etablierten Optionen:

Ansible

Das probably bekannteste IaC-Werkzeug. Ansible ist agentenlos (arbeitet über SSH), verwendet YAML für die Konfiguration und hat eine flache Lernkurve. Für FreeBSD-Administratoren ist es attraktiv, weil es native Module für ZFS, Jails, pkg und andere FreeBSD-Spezifika hat.

- name: ZFS-Dataset für Backup erstellen
  community.general.zfs:
    name: tank/backup
    state: present
    extra_zfs_properties:
      compression: zstd
      atime: off
      mountpoint: /backup

Der Nachteil: Ansible ist langsam bei großen Infrastrukturen und die YAML-Syntax wird bei komplexen Logiken unübersichtlich.

Terraform / OpenTofu

Für Cloud-Infrastrukturen ist Terraform (oder der Open-Source-Fork OpenTofu) der De-facto-Standard. Es verwaltet die Infrastruktur als Ressourcen — Instanzen, Netzwerke, Sicherheitsgruppen, Speicher — und hält den Zustand in einer State-Datei.

resource "aws_instance" "freebsd" {
  ami           = "ami-0xfreebsd15"
  instance_type = "t3.medium"

  tags = {
    Name = "freebsd-prod"
  }
}

Pulumi

Pulumi geht einen anderen Weg: Statt YAML oder HCL verwendet man echte Programmiersprachen — Python, TypeScript, Go. Das erlaubt echte Logik, Schleifen, Bedingungen und Typsicherheit.

import pulumi
import pulumi_command as command

server = command.remote.Command("freebsd-setup",
    connection=command.remote.ConnectionArgs(
        host="10.0.0.1",
        user="root",
    ),
    create="pkg install -y nginx",
)

Für FreeBSD: Besonderheiten

FreeBSD bringt eigene Werkzeuge mit, die in der IaC-Welt eine Sonderrolle einnehmen:

  • Jails sind leichtgewichtige Container, die sich hervorragend mit Ansible oder Shell-Skripten verwalten lassen.
  • ZFS bietet programmierbare Snapshots und Replikation, die sich in IaC-Workflows integrieren lassen.
  • pkgbase (seit FreeBSD 15.0) macht das Basissystem selbst paketierbar und damit IaC-kompatibel.

Der Pfad zur Einführung

IaC lässt sich nicht über Nacht einführen. Aber man kann schrittweise vorgehen:

  1. Bestandsaufnahme. Welche Server gibt es? Welche Konfigurationen? Was ist dokumentiert, was nicht?
  2. Ersten Server codifizieren. Den einfachsten Server nehmen und seine Konfiguration in Ansible (oder ein anderes Werkzeug) übertragen. Das dient als Lernprojekt und als Template.
  3. Neue Server nur noch via IaC. Jeder neue Server wird ausschließlich über Code konfiguriert. Keine manuellen Änderungen mehr.
  4. Bestehende Server migrieren. Nach und nach die manuelle Konfiguration durch IaC-Definitionen ersetzen. Das ist der langwierigste Teil.
  5. CI/CD für Infrastruktur. Änderungen an der IaC-Definition werden automatisch in Testumgebungen deployed, bevor sie auf Produktion gehen.

Die Kultur ändert sich mit

IaC ist nicht nur ein technischer Wechsel, sondern ein kultureller. Plötzlich sind Konfigurationsänderungen sichtbar. Jeder kann sie sehen, kommentieren, zurückrollen. Das ist ungewohnt — besonders für Administratoren.

Aber es ist der richtige Weg. In einer Welt, in der Sicherheitseinheiten täglich nachweisen müssen, welche Konfiguration auf welchem Server zu welchem Zeitpunkt aktiv war, ist manuelle Administration ein Risiko, das man sich nicht mehr leisten kann.

Und für den einzelnen Administrator ist IaC eine Erleichterung: Man muss sich nicht mehr erinnern, was man auf welchem Server gemacht hat. Es steht alles im Git-Repository. Wenn man nicht weiß, wie ein Server konfiguriert ist — man schaut nach. Immer. Zuverlässig. Ohne Ausnahme.

Automatisierung als Geschäftsmodell: Warum IT-Dienstleister ohne Automatisierung untergehen

Wer IT-Dienstleistungen verkauft, hat ein Problem: Seine Zeit ist begrenzt. Jede Stunde, die er an einem Kundensystem verbringt, ist eine Stunde, die er nicht für einen anderen Kunden aufwenden kann. Das Geschäftsmodell des klassischen IT-Dienstleisters — Stunden abrechnen, Probleme manuell lösen, individuell betreuen — hat eine harte Decke.

Automatisierung ist der Weg durch diese Decke. Und wer als Softwareentwickler und Administrator die Werkzeuge beherrscht, hat einen entscheidenden Vorteil: Er kann Automatisierung nicht nur anwenden, sondern bauen.

Das Problem mit dem Stundensatz

Ein klassischer IT-Dienstleister verrechnet vielleicht 80 bis 120 Euro pro Stunde. Wenn er 40 Stunden in der Woche arbeitet (realistisch sind es weniger, weil Akquise, Verwaltung und Reisezeit abgehen), ergibt das eine Umsatzdecke von etwa 160.000 bis 240.000 Euro im Jahr. Davon gehen Steuern, Versicherungen, Fortbildung, Arbeitsplatzkosten ab.

Skalierung ist in diesem Modell nur möglich, indem man Mitarbeiter einstellt. Aber jeder Mitarbeiter bringt neuen Verwaltungsaufwand, Schulungsbedarf, Qualitätskontrolle. Der Gewinn pro Kopf sinkt, wenn man nicht gleichzeitig die Effizienz steigert.

Was Automatisierung ändert

Automatisierung verändert die Mathematik. Statt eine Aufgabe einmal pro Kunde manuell zu erledigen, baut man sie einmal — und deployt sie x-mal.

Beispiel: Ein Kunde braucht einen Webserver mit Nginx, PHP-FPM, SSL-Zertifikaten und einer Monitoring-Lösung. Manuell dauert das — wenn man ehrlich ist — einen halben Tag. Mit Automatisierung dauert es beim ersten Kunden auch einen halben Tag (zuzüglich der Zeit für das Skript/Playbook). Bei jedem weiteren Kunden dauert es fünf Minuten.

Der Effekt: Die Kosten pro Deployment sinken drastisch, während die Qualität steigt. Automatisierte Deployments sind reproduzierbar, testbar, dokumentiert. Manuelle Deployments sind — wie oben beschrieben — Schneemänner.

Konkrete Automatisierungsfelder

Systemadministration

Alles, was auf einem Server konfiguriert wird, kann automatisiert werden:

  • Server-Setup — Basiskonfiguration, Benutzer, SSH-Keys, Firewall-Regeln
  • Dienst-Konfiguration — Webserver, Datenbanken, Mailserver, Monitoring
  • Updates und Patching — Automatisierte Aktualisierungen mit Rollback-Möglichkeit
  • Backup und Recovery — ZFS-Snapshots, Replikation, automatisierte Restore-Tests

Kundenschnittstelle

  • Onboarding — Neukunden bekommen automatisch ihre Infrastruktur
  • Reporting — Wöchentliche Statusberichte automatisch generiert und versendet
  • Abrechnung — Nutzungsbasierte Abrechnung direkt aus Monitoring-Daten
  • Ticket-Routing — Automatische Zuordnung von Support-Anfragen

Compliance und Dokumentation

  • Audit-Logs — Jede Änderung an der Infrastruktur ist in Git dokumentiert
  • Compliance-Checks — Automatisierte Überprüfung von Sicherheitsstandards
  • Disaster-Recovery-Tests — Regelmäßige, automatisierte Tests der Wiederherstellungsprozesse

Der Preis der Automatisierung

Automatisierung ist nicht kostenlos. Sie erfordert:

Zeit. Die Erstellung eines robusten Ansible-Playbooks dauert länger als die manuelle Konfiguration eines einzelnen Servers. Die Investition amortisiert sich erst ab dem zweiten oder dritten Deployment.

Kompetenz. Wer automatisiert, muss programmieren können. Nicht auf dem Niveau eines Software-Entwicklers, aber ausreichend, um Skripte zu schreiben, Datenstrukturen zu verstehen und Fehler zu diagnostizieren.

Wartung. Automatisierte Prozesse müssen gepflegt werden. Wenn sich Upstream-Software ändert, müssen die Playbooks angepasst werden. Wenn neue Anforderungen dazukommen, müssen sie integriert werden.

Aber — und das ist der entscheidende Punkt — diese Kosten fallen einmal an. Die manuellen Kosten fallen jedes Mal an.

Vom Dienstleister zum Produkt

Die konsequente Automatisierung öffnet einen Weg, der über das Dienstleistungsgeschäft hinausgeht: den Übergang zum Produkt.

Wenn die Infrastruktur-Einrichtung automatisiert ist, kann man sie als Self-Service anbieten. Der Kunde wählt seine Konfiguration über ein Web-Interface, das System richtet alles automatisch ein, und der Dienstleister muss nur noch überwachen und bei Problemen eingreifen.

Das ist der Weg, den erfolgreiche IT-Unternehmen gegangen sind: Hetzner mit der Robot-Weboberfläche, GitLab mit seinem CI/CD-Produkt, HashiCorp mit Terraform Cloud. Alle haben begonnen, Dienstleistungen manuell zu erbringen, und sie dann in Produkte verwandelt.

Für kleine IT-Dienstleister bedeutet das nicht, dass man ein SaaS-Startup werden muss. Aber es bedeutet, dass man seine wiederkehrenden Aufgaben identifizieren, automatisieren und als Paket anbieten kann — zu einem Preis, der manuell nicht erreichbar ist.

Der erste Schritt

Wer mit Automatisierung anfangen will, sollte nicht versuchen, alles auf einmal umzustellen. Der beste erste Schritt ist:

  1. Den häufigsten wiederkehrenden Prozess identifizieren
  2. Ihn einmal vollständig automatisieren
  3. Die Zeitersparnis messen
  4. Den nächsten Prozess angehen

Bei mir war das die ZFS-Replikation mit Syncoid. Ein Prozess, der vorher jeden Abend manuell überprüft werden musste und regelmäßig Probleme verursacht hat. Nach der Automatisierung läuft er im Hintergrund — zuverlässig, reproduzierbar, fehlerfrei.

Die Zeit, die ich dadurch gewonnen habe, habe ich in die nächste Automatisierung investiert. Und die nächste. Irgendwann war der Punkt erreicht, an dem ich mehr Zeit für echte Problemlösung hatte als für wiederkehrende Aufgaben.

Das ist das Versprechen der Automatisierung. Und es hält, was es verspricht — wenn man den anfänglichen Aufwand investiert.

Was ist neu in Qt 6.10? Ein Überblick für Entwickler

Qt 6.10 ist ein klassisches „Framework‑Release“, das an vielen Stellen nachzieht, wo sich in den letzten Jahren Anforderungen und Best Practices geändert haben: moderneres UI‑Layouten mit Flexbox, stärkere Unterstützung für Vektoranimationen (SVG/Lottie), vereinfachte Datenanbindung zwischen C++ und QML, neue Hilfstypen für Modelle und Bindungen – und dazu ein spürbares Update bei Accessibility und Plattformintegration.

Im Folgenden ein Überblick über die wichtigsten Änderungen von Qt 6.10, auf Basis der offiziellen Release‑Informationen.

Accessibility: High Contrast und Screenreader werden ernster genommen

Qt 6.10 legt sichtbar mehr Wert auf Barrierefreiheit:

  • High‑Contrast‑Mode auf allen Plattformen:
  • Die eingebauten Styles orientieren sich stärker an den jeweiligen System‑Einstellungen für hohen Kontrast.
  • Ziel: Qt‑Apps sollen sich optisch nahtlos in die restliche Oberfläche einfügen und dabei besser lesbar sein.
  • Für dich als Entwickler bedeutet das: Ohne Codeänderung profitierst du von verbessertem Kontrast, wenn Nutzer das systemweit aktivieren.
  • Bessere Integration mit Assistive Technologies:
  • Qt Widgets und Qt Quick Controls wurden überarbeitet, damit Screenreader und andere Hilfsmittel sauberer angesprochen werden.
  • Besonders für WebAssembly gab es Verbesserungen in der Accessibility‑Implementierung.
  • Viele Änderungen fließen auch in LTS‑Branches zurück (Patch‑Releases), sofern du dort aktuell bleibst.

Unterm Strich: Qt 6.10 hilft dir bei der Einhaltung von Accessibility‑Vorgaben, ohne dass du an jeder Ecke Speziallogik schreiben musst.

Qt Quick: FlexboxLayout und moderne UI‑Bausteine

Qt Quick bleibt die Speerspitze für neue UI‑Konzepte. Mit Qt 6.10 kommen unter anderem:

FlexboxLayout (Tech Preview)

  • Neues Layout‑Element FlexboxLayout für Qt Quick, das sich an CSS Flexbox anlehnt.
  • Vorteile:
  • Besseres Verhalten bei unterschiedlich großen Screens und Aspect Ratios.
  • Weniger Custom‑Layoutcode für „responsive“ UIs.
  • Vertraut für alle, die bereits mit Web/CSS arbeiten.
  • Integration:
  • Bindet sich in das bestehende Layout‑System von Qt Quick ein (attached properties etc.).
  • Ist als Technologievorschau gekennzeichnet – API kann sich bis zum nächsten LTS noch ändern.

Animierte Vektorgrafiken (SVG & Lottie)

Qt 6.10 baut konsequent auf den SVG/Vektor‑Verbesserungen der vorherigen Versionen auf:

  • VectorImage (aus 6.8 bekannt) wird erweitert:
  • Unterstützung für animierte Vektorgrafiken in
    • SVG‑Format und
    • Lottie‑Format.
  • Qt Lottie‑Modul:
  • Deutlich verbesserte Unterstützung moderner Lottie‑Dateien.
  • Lottie‑Assets können jetzt als skalierbare, hardwarebeschleunigte Vektorgrafiken direkt im Qt‑Quick‑Scenegraph gerendert werden.

Für UI‑Designer bedeutet das: Aufwendige, aber leichtgewichtige Animationswelten lassen sich direkt aus Design‑Tools (Figma/After Effects → Lottie) in Qt übernehmen.

Neuer Quick Control: SearchField

  • Spezialisierter Eingabebaustein für Suchfelder.
  • Bringt:
  • nativen Look & Feel auf allen Plattformen (wie andere Qt Quick Controls),
  • integrierte Vorschlagsliste mit Modellanbindung.
  • Integration:
  • suggestionModel kann über die üblichen Mechanismen (QAbstractItemModel, Kontextobjekte, QML‑Modelle) befüllt werden.
  • Besonders interessant in Kombination mit den neuen Modell‑/Bindungswerkzeugen (siehe unten).

Einfachere Verbindung zwischen C++‑Daten und QML‑UIs

Ein klassischer Schmerzpunkt in Qt‑Projekten war die Verbindung zwischen C++‑Backend und QML‑UI. Qt 6.10 nimmt sich genau dieser Nähte an.

QRangeModel: C++‑Container direkt als Modell

  • QRangeModel ist eine schlanke QAbstractItemModel‑Implementierung, die C++‑Ranges (z.B. std::vector, std::array, beliebige iterierbare Container) direkt als Modell zur Verfügung stellt.
  • Eigenschaften:
  • Kann einfache Typen (int, QString, …) wie auch komplexe Typen (GADGETs, std::tuple) abbilden.
  • Modellrollen werden automatisch erzeugt.
  • Funktioniert gleichermaßen in Qt Widgets (Views) und in QML/Qt Quick.
  • Beispiel‑Anwendung:
  • std::vector<int> als Liste in einer QML‑ListView,
  • std::vector<MyGadget> als typ‑sicheres Modell in Delegates mit required property.

Damit entfällt für viele Anwendungsfälle das Schreiben eigener QAbstractItemModel‑Subklassen.

delegateModelAccess: Zurückschreiben in das Modell vereinfachen

Bisher war das Schreiben aus einem Delegate zurück in das Modell oft umständlich:

  • Entweder über model‑Objekte im Delegate
  • oder über Kontextproperties und eigene Signal‑Handler.

Mit Qt 6.10 kann eine View über delegateModelAccess: DelegateModel.ReadWrite explizit erlauben, dass required‑Properties im Delegate direkt zurück ins Modell schreiben. Das reduziert Boilerplate deutlich, insbesondere in größeren QML‑UIs.

Synchronizer: Zwei‑ und Mehrwege‑Bindungen

  • Neues Element Synchronizer (Tech Preview, Modul Qt.labs.synchronizer).
  • Zweck:
  • Mehrere Properties so synchron halten, dass sie (so weit möglich) denselben Wert haben, ohne klassische Bindungen zu „brechen“.
  • Funktioniert für Kombinationen von C++‑ und QML‑Eigenschaften.
  • Praxisnutzen:
  • Typische „Slider ↔ Modell‑Wert“‑Szenarien lassen sich deklarativ und ohne zusätzliche Signal‑Handler abbilden.

TreeModel für QML

  • Neues QML‑TreeModel, mit dem sich Baumdaten direkt in QML deklarieren lassen.
  • Zielgruppe:
  • Prototyping,
  • kleinere Datenmengen,
  • Szenarien, in denen ein kompletter C++‑Baummodell‑Layer Overkill wäre.

Zusammen genommen macht Qt 6.10 die Kante zwischen C++‑Backend und QML‑Frontend deutlich angenehmer.

Qt Graphs: FilledSurface und mehr

Qt Graphs wird auch in 6.10 weiter ausgebaut:

  • Neue Diagrammtypen und Anpassungen:
  • u.a. ein neuer „FilledSurface“‑Graph zur besseren Darstellung gefüllter Flächen.
  • Bessere Integration in Qt Quick und die neuen Layout‑/Vektorfeatures.

Wenn du bereits mit Qt Graphs arbeitest, lohnt sich ein Blick in die konkreten Release Notes für dieses Modul.

Sonstige Verbesserungen und Plattform‑Updates

Wie bei jedem Qt‑Release gibt es eine Reihe weiterer Verbesserungen:

  • Plattformintegration:
  • Qt 6.10 richtet sich nach den jeweils aktuellen Versionen der großen Desktop‑, Mobile‑ und Embedded‑Plattformen (siehe Release Note und Wiki‑Seite).
  • Bugfixes und Feinschliff:
  • Dutzende Fehlerkorrekturen in den Untermodulen (Widgets, Quick, Network, etc.).
  • Viele Details lassen sich in den detaillierten Release Notes (6.10.0–6.10.2) nachlesen.

Fazit

Qt 6.10 ist kein „großer Sprung“ im Sinne völlig neuer Konzepte, sondern ein Release, das viele typischen Alltagsbaustellen adressiert:

  • Accessibility wird ernst genommen (High Contrast, Screenreader‑Integration).
  • Qt Quick bekommt mit FlexboxLayout, animierten Vektorgrafiken und SearchField Werkzeuge, die aktuelle UI‑Designs besser abbilden.
  • Die Verbindung zwischen C++‑Daten und QML‑UIs wird durch QRangeModel, delegateModelAccess, Synchronizer und TreeModel deutlich entschärft.

Wer bereits auf Qt 6.x unterwegs ist, sollte Qt 6.10 vor allem dann in Betracht ziehen, wenn:

  • Accessibility und regulatorische Vorgaben eine Rolle spielen,
  • moderne, animierte UIs (Vektor/Lottie) benötigt werden,
  • oder die Brücke zwischen C++‑Backend und QML‑Frontend bislang viel Handarbeit erfordert.

Quellen

  • Qt Blog: Qt 6.10 Released! – https://www.qt.io/blog/qt-6.10-released
  • Qt Wiki: Qt 6.10 Release – https://wiki.qt.io/Qt_6.10_Release
  • Qt Doku: New Features in Qt 6.10 – https://doc.qt.io/qt-6.10/whatsnew610.html

KooKooK: App für neurodivergente Menschen als Testballon

Vor einiger Zeit wollte ich mich mit QML näher auseinandersetzen und suchte nach einer Projektidee. Als Domain hatte ich noch „kookook.org“ bei mir registriert und dachte, dass ich einfach damit was mache. Bei der Projektidee ging es, allen voran, darum, dass ich mich mit dieser Technik auseinandersetzen und mich vor allem auf mobile Plattformen (iOS, Android) konzentrieren wollte.

Ich habe mich entschieden, an einer App für neurodivergente Menschen zu arbeiten, um ein Ziel vor Augen zu haben. Herausgekommen ist jetzt eine kleine App, mit der man seine Stimmungen und Reize tracken kann. Das Programm kann noch nicht viel, aber vielleicht interessiert es jemanden.

Hier sind ein paar Screenshots:

Es gibt auch eine Android-Version, die ist im Google Play Store allerdings noch nicht freigegeben, da ich dafür erst 12 Tester benötige und mir dazu gerade die Zeit fehlt. Wer Lust hat: Gerne per E-Mail an mich, ich schalte die Version dann frei.

Die App ist kostenlos und benötigt keine Internetverbindung.

Softwareentwicklung Teil 2: Weitere Erfahrungen

Mir fallen noch einige weitere Dinge ein, die ich hier zu teilen versuche. Meist geht es um technische Schulden und, für mich, komische Ansätze in der Verwaltung von Firmen.

Ich war vierzehn Jahre lang in einem Unternehmen beschäftigt und das hat, zumindest in Bezug auf die IT, auf die IT-Abteilung gehört. Haben wir immer die richtigen Entscheidungen getroffen? Nein. Aber zumeist und aus den fehlgeschlagenen Entscheidungen haben wir immer gelernt. Ich möchte das hier einmal als Positivbeispiel anbringen. Ich schätze, es muss 2012 gewesen sein, als wir neue Server anschafften. Zwei baugleiche Geräte für Redundanz. Wir kamen auf die Idee, dort Festplatten mit 4TB Speicherkapazität einzubauen und entschieden uns für Western Digital SAS. Leider wusste keiner von uns, und da hätten wir uns vorher definitiv noch einmal genauer informieren müssen, dass es SAS-Festplatten und Nearline-SAS-Festplatten gab. Wir waren zwar verwundert über die Preise, denn eine solche Platte mit 4TB in etwa so viel wie welche mit 960GB, aber wir forschten nicht weiter nach, sondern freuten uns.

Wir klatschten die Server also mit einer Menge dieser Platten voll, richteten darauf zraid-2 ein (RAID 6) und banden die Geräte ins Netzwerk ein. Wie zuvor auch, exportieren wir die Home-Laufwerke gut 50 Clients per NFS. In Tests funktionierte alles tadellos und wir schlossen glücklich und schnell die Umstellung ab. Dann kamen die Leute und wollten arbeiten. Es kam zu großen Wartezeiten und ein gewisser Unmut machte sich breit, denn das System performte nicht. In einzelnen Tests lief es hervorragend, sequentielles Schreiben und Lesen funktionierte tadellos. Aber in der Masse und bei der Menge an Dateien war es grottenlangsam und unbenutzbar. Wir suchten zu zweit sicher einen Monat nach dem Problem, bis ich auf die Idee kam, dass die Platten in Form der Hardware schuldig waren. Wir stellten dann ein solches Szenario nach und stellten dem gegenüber ein System mit echten (super teuren) SAS-Festplatten und siehe da: Genau da war das Problem. Die Lösung war schnell da: Neue Festplatten mussten her. Wir besprachen das mit der Geschäftsleitung, räumten ein, dass es letztlich unsere Schuld war, wir das aber vorher nicht wussten und es kein böser Wille war. Das Ende vom Lied war, dass wir neue Festplatten, die teuer waren und eine niedrige Kapazität hatten, kauften und einbauten. Das kostete die Firma natürlich eine Unmenge an Geld (ich habe noch gut 12.000 Euro im Kopf). Uns wurde aber nicht der Kopf abgerissen. Erstens wäre der weitere Betrieb in alter Form ohnehin teurer geworden, da niemand arbeiten konnte, und zweitens wusste man, dass Fehler passieren. Wir haben das zusammengefasst, noch einmal berichtet, was wir gelernt hatten, und solche Probleme traten dann nie wieder auf.

In einer anderen Firma sprach ich einmal an, dass wir einen gewissen Style-Guide einführen sollten, und dieser bezog sich nur auf die Benennung von Variablen, Konstanten und Funktionen. Die Benennung solcher Dinge kann man weiter unten in meinem vorherigen Artikel nachlesen, da habe ich ein Beispiel. Ich sprach mich für „sprechende“ Namen aus. Dies wurde abgelehnt, denn dann hätte man ewig lange Namen, mehr aussagen würden diese auch nicht, und man würde sich tottippen (VI(M) war der Editor der Wahl und mit [CTRL]+[p] bzw. [CTRL]+[n] ergänzt er begonnene Namen vollautomatisch). Aufgrund der Ablehnung und auch aufgrund anderer, vorheriger und späterer Aussagen, war mir klar, dass da keine zielbringende Diskussion möglich war. Also ließ ich es.

In der selben Firma kam man auf die Idee, die (teuer zu bezahlenden) Mitarbeiter ein bis mehrmals pro Woche (später dann die Entwickler, die an einem gewissen Projekt arbeiteten, alle zwei Wochen) halbtägig in den technischen Service zu stecken. Der Tenor, so ich mich noch richtig erinnere, war, dass diese dann mehr vom Drumherum mitbekommen und Prozesse besser verstehen. Man war dann in der Tickethölle und musste bestimmte, ausgewählte, redundante Aufgaben abarbeiten. Das Problem: Für viele Serviceaufgaben gab es entweder keine Tools oder diese waren so dermaßen komplex, fehleranfällig und schwergängig, dass sie ein „normaler“ Servicemitarbeiter nicht hätte benutzen können. Bereits einfache Aufgaben konnten ganze Prozesse zerschießen. Anstatt die Softwareentwickler laut ihrer Kompetenzen dazu zu bringen, Tools zu entwickeln, die der Service nutzen hätte können, nutzten wir die halbgaren Tools in der Hoffnung, nichts Schlimmeres zu machen. Doch trotz großer Vorsicht passierte dies ab und an, auch mir zwei Mal. Einmal, ich weiß es noch, haben ein Kollege und ich mehr als einen halben Tag daran gesessen, das Problem zu fixen. Dabei wäre es wirklich sinnvoller gewesen, diese Tools robust zu machen.

Mir fällt noch ein Beispiel in dieser Firma ein. Wir hatten einen Workshop und mussten danach irgendwelche Funktionen noch fertig machen. Beim Testen wurde bei einem der komplexen Parameter aus Versehen die falsche Datenbank angegeben. Keinem von uns, wir waren drei oder vier Leute, fiel dies auf. Leider wurden dann wichtige Datensätze von Kunden in der Produktivumgebung überschrieben bzw. gelöscht. Die Produktivumgebung für mehrere tausend Kunden war nicht vollständig von der Entwicklungsumgebung abgeschirmt. Mein Chef hat es zwar hinbekommen und war auch nicht böse, aber es hätte auch anders ausgehen können. Beim Vorschlag, dass sowas irgendwie anders gelöst wird, kam nur ein lapidares „Nutzen Sie doch einfach die richtige Datenbank.“. Schlussendlich wurde doch zumindest ein Parameter im Programm umbenannt.

Es gibt an dieser Stelle zwei wichtige Dinge:

  1. Die Fehlerkultur in einem Unternehmen bestimmt auch die Qualität der Software, die Weiterentwicklung dieser, die der Entwickler und zu guter Letzt die des Unternehmens.
  2. Das Unternehmen sollte unbedingt die Vita der Leute, die es beschäftigt, ansehen. Wer kann wo am besten eingesetzt werden? Wert hat wo die besten Erfahrungen? Usw. usf. Das wurde in einigen Unternehmen, in denen ich war, nicht getan.

Die schrecklichste Zeit, die ich je hatte, waren meine zwei Monate bei einem Softwareunternehmen in Koblenz. Das Unternehmen hatte unglaublich viele Probleme. Neben der bescheidenen Bezahlung für die Programmierer war allen voran die Qualität des Codes völlig unzulänglich. Niemand sah sich meine Vita an, doch einer meiner Programmierkollegen meinte irgendwann: „Er soll sich doch mal die Memory-Leaks in unserer Software ansehen, er kennt sich da aus.“

Ich wühlte mich also durch etliche Zeilen kaum lesebaren Codes, da es auch hier keinen einheitlichen Style gab. Viel schlimmer war aber, dass ich nur Zugriff auf einen auf ein Core-System aufsetzenden Code hatte, aber nicht auf das Core-System selbst. Im Core-System gab es aber etliche Probleme. Zugriff bekam ich trotzdem nicht, so dass ich meiner Aufgabe überhaupt nicht sinnvoll nachgehen konnte. Dass nur ich das alles kaum verstand, sah man am Versionsverwaltungssystem (Subversion): Von den meisten Kollegen gab es maximal einen Commit pro Woche und der Commit hatte meistens nur ein bis drei Codezeilen inne. Niemand stieg durch das System.

Auch die Aufteilung innerhalb dieser Firma war äußerst komisch. Es kam SAFE zum Einsatz, das aber nur nebenher. Aufgeteilt wurde die Entwicklung zwischen zwei Menschen: dem Requirements-Engineer (kurz RE) auf der einen, dem Programmierer auf der anderen Seite. Gehen wir von einer Rolle als Senior-Softwareentwickler (was auch immer das sein soll) aus. Der RE bekam den Auftrag für ein neues Modul oder einen Teil eines Moduls. Dieser beschrieb dann, was gemacht werden sollte (aus meiner Sicht noch ok) und dann unterteilte er es in etliche Untertasks. D.h. der RE musste dem Softwareentwickler seine eigenen Kompetenzen wegnehmen und für ihn planen, wie der Softwareentwickler dies umzusetzen hatte. Und der Softwareentwickler musste auf diese Tickets seine Zeiten buchen (das war übrigens die Hauptaufgabe: Verwalten seiner Zeiten, jede Sekunde musste protokolliert werden) und sich dafür rechtfertigen, wenn er länger brauchte oder Dinge nicht funktionierten. Das habe ich in den zwei Monaten, in denen ich da war, öfter erlebt. Man musste sich vor seinem Vorgesetzten und mitunter vor dessen Vorgesetzten verantworten. Es war die pure Hölle, was ich mittlerweile aber auch verstehen kann, weiß ich doch mittlerweile, in welcher Szene sich der Gründer des Unternehmens widerwärtig aufhält.

Kommen wir noch einmal auf die erste Firma zurück. Dort war eines der Probleme, wie ich in einem anderen Artikel bereits schrieb, dass unglaublich viel Code generiert wurde. Dabei ging es um eine Art OR-Mapper für DBMS und XML. Objektorientierte Entwicklung und generische Programmierung wurden hier immer wieder abgelehnt, obwohl diese unglaublich viele Probleme gelöst hätten. Man entschied sich für die Erneuerung des Codes für eine Multiparadigmensprache. Diese kann zwar Objektorientierung, aber nicht wirklich Vererbung. Warum die Wahl auf diese Programmiersprache fiel, war mir nie klar. Letztlich wurde das damit bekräftigt, dass die neue Generation von Programmierern kein C mehr kann. Auf C basierte die meiste alte Software (wenig auf C++, Ruby, Python, Shell-Scripts, usw.). Die Wahl hielt ich für suboptimal. Ein sinnvoller Weg wäre vielleicht gewesen, auf C++ umzusteigen. Da ein Projekt bereits in C++ umgesetzt war, waren auch schon bestimmte Kompetenzen vorhanden. Auch hätte man einen Teil des alten Codes leichter weiterverwenden können, als es mit der ausgewählten Programmiersprache möglich war (wenn diese auch C unterstützte). Die Ablösung wäre vielleicht einfacher gewesen, aber natürlich auch, dass Programmcode 1:1 übernommen worden wäre, was vielleicht nicht das eigentliche Ziel war. Es wurde allerdings Code übernommen und nahezu 1:1 in die neue Programmiersprache gesetzt. Variablen hießen gleich, Funktionen hießen gleich, der Programmablauf war der gleiche.

Zum Einsatz kamen zwei DBMS. Ein teures von einem teuren Hersteller und, für das neue Projekt, ein super gutes, welches ich auch oft empfehle. Beide DBMS wurden aber nicht wirklich als DBMS genutzt, sondern nur als Puffer für irgendwelche Daten. Auch auf vernünftige referentielle Integrität wurde, so wie ich die Datenstrukturen wahrnahm, verzichtet. Je nachdem, ob man in der Entwicklung war und Daten löschen wollte, musste man die händisch aus etlichen Tabellen entfernen. Von Normalisierung und Stored Procedures usw. müssen wir gar nicht sprechen.

Softwareentwicklung: Verwaltung zuerst – aber wie steht es um Softwarequalität?

In den letzten Jahren habe ich in verschiedenen Unternehmen gearbeitet, die zwar unterschiedlich waren, aber mit ähnlichen Problemen konfrontiert waren. Mit diesem Text möchte ich meine Perspektive auf diese Herausforderungen teilen.

Als Softwareentwickler und Administrator habe ich an zahlreichen Projekten im Softwarebereich, in der Administration sowie im Aufbau von Netzwerken und Client-Server-Strukturen gearbeitet. Einige dieser Projekte habe ich selbst geleitet, andere in Zusammenarbeit mit verschiedenen Personen betreut.

In meinen letzten Positionen war ich jedoch hauptsächlich auf die Programmierung beschränkt. Ich hatte keine Entscheidungsbefugnis und konnte mein Wissen und meine Expertise nicht sinnvoll einbringen. Stattdessen führte ich eine monotone und ermüdende Fließbandarbeit aus. Diese Erfahrung ermöglichte es mir jedoch, die Probleme aktueller Softwareunternehmen zu beobachten, die in einem ewigen Kreislauf der Selbstoptimierung gefangen sind, aber im IT-technischen Kernbereich keine bedeutenden Fortschritte erzielen.

Zwei Hauptthemenbereiche traten in diesen Unternehmen hervor (nicht in jedem, aber mindestens in einem):

  1. Die Notwendigkeit, agil zu werden und zu bleiben.
  2. Die Implementierung von CI/CD um jeden Preis.

Für die meisten klingen diese beiden Punkte sinnvoll, und in gewisser Weise sind sie es auch, insbesondere der zweite Punkt. Die Umsetzung dieser Ansätze erfolgte jedoch nicht als strukturierter Prozess, sondern eher als eine übergeordnete Aufgabe, die den Fokus von den wirklich wichtigen Aufgaben ablenkte.

Beginnen wir mit dem Thema Agilität. Was neue Softwarefirmen (Startups) von Anfang an praktizieren, wird in etablierten Unternehmen oft nur mühsam eingeführt. Ich erinnere mich noch gut daran, wie wir uns in einem Unternehmen, das von technischen Schulden geplagt war, ausschließlich auf die Einhaltung agiler Prinzipien konzentrierten, anstatt die eigentlichen Probleme anzugehen. Das bedeutete, dass wir mit Hochdruck Tools einführten und Schulungen durchführten, die die Mitarbeiter hauptsächlich beschäftigten. Da es Architekten, Product Owner und Scrum Master und so weiter gab, wollte kaum noch jemand Techniker sein, sondern einen solchen Titel tragen und Tickets und Epics durch die Gegend schieben. Das Softwareprodukt selbst blieb dabei auf der Strecke.

Wir hatten mehrere Schulungen mit einem Unternehmen, das sich meiner Meinung nach auf die Vermittlung esoterischer Agilität spezialisiert hatte. Alle zwei Wochen fand die Retrospektive statt, in der jeder seine Gefühle offenbaren musste und wir uns an wilden (Kinder-)Spielen wie „Wer ist schneller mit dem Mauszeiger?“ beteiligten. Wichtige Themen wie Bugs, Features, Refactoring, Neuausrichtung, Ideen und die Erweiterung unseres technischen Wissens wurden dabei völlig vernachlässigt. Stattdessen mussten wir uns gegenseitig loben und betonen, wie großartig unser Team sei. Das Produkt blieb oft ein einziges Chaos, und mir war die ganze Nummer mehr als peinlich.

Fahren wir mit CI/CD fort. Obwohl ich es für wichtig halte, ist es nicht so entscheidend wie das Produkt selbst. In einer Firma musste ich ein Frontend entwickeln, das zwei Kommandozeilenprozesse startete und überwachte. Es war eine relativ einfache Software, die schnell geschrieben werden konnte. Tatsächlich musste ich sie zweimal schreiben. Zuerst verwendete ich Qt und C++, was zu einem funktionsfähigen, modernen und effizienten Produkt führte. Es wurde jedoch entschieden, dass es einfacher sein und lieber mit wxWidgets geschrieben werden sollte, da die Firma bereits Erfahrung mit dieser Technologie hatte. Daher begann ich mit dem Schreiben einer neuen Version. Obwohl der Funktionsumfang geringer war, dauerte die Entwicklung aufgrund der geringeren Abstraktion von wxWidgets länger. Schließlich war das Produkt fertig, funktionsfähig und bereit für die Auslieferung. Es handelte sich um eine relativ kleine Codebasis von etwa 4.000 Zeilen C++. Nachdem ich das Produkt fertiggestellt hatte, hatte ich aufgrund von schlechtem Management (man war ja mit Agilität beschäftigt) nichts mehr zu tun. Man schlug vor, dass ich mich mit dem Testing befassen sollte, da das Produkt in CI/CD integriert werden musste. Dies umfasste drei Hauptaspekte:

  1. Unit- und Integrations-Tests mit Google-Test
  2. Statische Codeanalyse mit SonarQube
  3. Automatische GUI-Tests

Ich habe mich dann über ein halbes Jahr ausschließlich mit diesem Projekt beschäftigt. Während die Unit- und Integrations-Tests noch relativ einfach zu handhaben waren, erwies es sich als deutlich schwieriger, Anwendungsfälle für eine Software mit über 4.000 Zeilen Quellcode zu entwickeln, von denen der Großteil GUI-bezogen war. Das agile Testmanagement verlangte eine Code-Coverage von mindestens 70 %. Anstatt mich also auf die eigentliche Kernsoftware zu konzentrieren, die dieses von mir entwickelte Frontend lediglich startete und überwachte, widmete ich mich der ABM und der Erstellung von Tests, die letztendlich keinen wirklichen Zweck erfüllten. Der Grund dafür ist einfach: Die Software war funktionsfähig, sollte nicht weiterentwickelt werden und war nicht anfällig für Fehler. Sie war ausgebaut und lediglich im Bestand. Darüber hinaus sollte sie in naher Zukunft durch eine andere Software ersetzt werden.

Trotz dieser Umstände durfte ich mich weiterhin mit der Umsetzung der teils eigenwilligen Standard-Regeln von SonarQube befassen. In den gesamten 4.000 Zeilen Code entdeckte SonarQube lediglich einen einzigen Bug (einen gelöschten Pointer, der in einem anderen Codesegment erneut aufgerufen wurde). Die restlichen Hinweise bezogen sich auf unbedeutende Aspekte wie die Anzahl der Member-Variablen und die Begrenzung der Methodenanzahl pro Klasse auf 30.

Da die Software auch zwei klickbare Buttons enthielt, musste ich vollautomatische GUI-Tests implementieren. Dies stellte sich bei einer wxWidgets-Anwendung mit C++ als Herausforderung dar, konnte aber erfolgreich gemeistert werden. Dadurch wurde das gesamte GUI vollautomatisch testbar.

Obwohl dies die Software, die im Mittelpunkt stand, nicht direkt voranbrachte, fügte es doch ein weiteres Puzzleteil zur Pipeline hinzu. Ich konnte wertvolle Erkenntnisse gewinnen, die ich bei zukünftigen Softwareprojekten, wo es sinnvoll ist, anwenden kann.

In einer anderen Firma war ich an zwei oder drei Softwareteilen beteiligt. Auch hier wurde, im Zuge des Wachstums des Produkts, zunehmend Wert auf die Pipeline gelegt. Folglich mussten zahlreiche Tests nachimplementiert werden. Dies war nur bedingt sinnvoll, da drei wesentliche Probleme vorlagen:

  1. Die Qualität des Codes und insbesondere der gesamten Architektur war mangelhaft, wenn nicht gar nicht vorhanden.
  2. Es gab Fachverfahren, die eine umfassende Einarbeitung erforderten oder eine gezielte Einweisung notwendig gemacht hätten.
  3. Die Software sollte vollständig durch eine neue Version in einer anderen Programmiersprache ersetzt werden. Diese neue Architektur war jedoch ebenfalls fehlerhaft und entsprach nicht den Qualitätsstandards, die ich vertrete.

Einige der Tests hätten durchaus auch für die zweite Generation der Software verwendet werden können, was sinnvoll war, um das Verhalten der alten und neuen Software zu vergleichen. Doch meiner Meinung nach war das Projekt dazu verdammt, gegen die Wand zu fahren.

Unit-Tests, Integrationstests, Code-Reviews, CI/CD, statische Codeanalyse, GUI-Tests, Dokumentation, nachverfolgbare Ticketbearbeitung, Kompetenztransfer und vieles mehr sind entscheidend für eine nachhaltige Softwareentwicklung. Diese Elemente sollten jedoch von Anfang an integriert sein. Sie später, insbesondere bei großen Projekten, einzuführen, ist ineffektiv, vor allem bei komplexen Projekten mit Hunderttausenden von Codezeilen. Darüber hinaus können andere technische Schulden so hoch sein, dass sie dringendere Aufmerksamkeit erfordern.

Ich habe es immer wieder erlebt, dass Unternehmen weiterhin auf veraltete Frameworks setzen. Ich bin auf Systeme gestoßen, die 20 Jahre alt oder noch älter waren und längst nicht mehr unterstützt wurden. Oder auf Plattformen, die über 20 Jahre alt waren und auf denen immer noch die Software für aktuelle Systeme kompiliert wird, weil die Migration auf aktuelle Plattformen vernachlässigt wurde.

Doch das ist nicht alles. Die Qualität von Software-Code ist ein entscheidender Faktor in der Softwareentwicklung. Ich habe Ein-Personen-Projekte erlebt, die aufgrund ihrer zunehmenden Komplexität oder der Sorge um die langfristige Verfügbarkeit des ursprünglichen Entwicklers zusätzliche Teammitglieder erforderten. Diese neuen Teammitglieder haben jedoch oft Schwierigkeiten, den Code, die Fachverfahren und das gesamte System zu verstehen.

Aber warum ist das so? Ein Ein-Personen-Projekt hat von Natur aus seine Grenzen. Der ursprüngliche Entwickler versteht den Code vielleicht noch, aber das gilt nicht unbedingt für andere. In den letzten Jahren bin ich immer wieder auf schlecht geschriebenen Code gestoßen. Schon die Verwendung von Funktionen, Methoden oder Variablennamen wie „reg_rq_fachver2_23“ ist wenig hilfreich. Darüber hinaus habe ich unglaublich redundanten Code gesehen, wie zum Beispiel:

int za_wwggw_w2(int p, int p_k, int p_key, int k, int key, char *pk) {
int _key;
struct pkey *pkey_p;
return za_wwggw_w3(p, p_k, p_key, k, key, pk, &_key, pkey_p);
}

Selbst nach mehrmaligem Lesen verstehe ich diesen Code nicht. Wenn ich mich durch etwa 50 Dateien mit mehreren zehntausend Zeilen Code kämpfen müsste, der genauso oder noch schlimmer aussieht, würde ich irgendwann aufgeben.

Es gab Software, bei der GUI-Komponenten mit Namen wie Edit1, Edit2, Edit3 bis Edit123 versehen waren. Diese Praxis führte zu immensen technischen Schulden, die ich nicht erklären kann. Schließlich ist allgemein bekannt, dass sauberer und lesbarer Quellcode die Notwendigkeit von Dokumentation minimiert (die oft ohnehin nicht vorhanden ist), das Bugfixing und die Wartbarkeit erhöht sowie die Einarbeitung anderer Menschen vereinfacht.

Betrachten wir das Projekt mit der Methode za_wwggw_w2. Es war offensichtlich, dass das Projekt unkontrolliert gewachsen war und eine Reimplementierung erforderlich war. Meiner Meinung nach war dies der einzige praktikable Ansatz, um das Projekt weiter auszubauen. Allerdings sah ich sofort mehrere Probleme:

  1. Die Reimplementierung wurde nicht als eine vollständige Neubegründung des Projekts verstanden, was angesichts seiner Komplexität eine gewaltige Aufgabe gewesen wäre. Stattdessen wurde sie als eine Portierung des alten Codes auf eine neue Programmiersprache wahrgenommen, mit minimalen Anpassungen, um die Besonderheiten der neuen Sprache zu berücksichtigen. Als ich den Code der anderen Programmierer untersuchte, stellte ich fest, dass er fast identisch mit dem alten Code war, mit nur wenigen geringfügigen Änderungen. Die zugrundeliegenden Probleme blieben bestehen, und ohne jemanden direkt verantwortlich machen zu wollen, würde ich behaupten, dass die meisten, die an dieser Umsetzung beteiligt waren, sie nicht vollständig verstanden.
  2. Darüber hinaus wurde im Prozess keine Architektur implementiert. Da die neue Programmiersprache eine einfache Integration von Code aus dem alten System ermöglichte, wurde diese Funktion häufig genutzt.
  3. Es wurde eine Masse an „gleichem“ Code automatisch generiert, anstatt auf Abstraktion, Ableitung und Konventionen zu setzen. Viele tausende Zeilen gleicher Code mit leicht unterschiedlicher Logik wurde generiert.

Leider wurden die gleichen Fehler gemacht wie bei dem Ein-Personen-Projekt, obwohl das Team aus erfahrenen Programmierern bestand, die jahrelange und jahrzehntelange Erfahrung mitbrachten. (Ich kam relativ spät dazu und wurde hauptsächlich als „Programmieräffchen“ eingestellt.)

Diese Erfahrung habe ich in zahlreichen Projekten gemacht. In einem Projekt, das stark auf eine Datenbank angewiesen war, deaktivierte mein Vorgänger die referentielle Integrität mit der Begründung, es würde die Leistung verbessern. Dies führte jedoch dazu, dass die Datenbank in einen fehlerhaften Zustand geraten konnte (was auch mehr als nur einmal passierte). Solche Probleme hätten leicht behoben werden können, indem beispielsweise ein zuverlässiges Datenbankmanagementsystem (DBMS) verwendet oder qualitativ hochwertiger Code geschrieben worden wäre. Trotzdem wurden diese Maßnahmen nicht ergriffen.

Meine Botschaft ist klar: Anstatt sich ausschließlich auf das Umfeld zu konzentrieren, würde es vielen Produkten zugutekommen, wenn ein stärkerer Fokus auf die Produkte selbst gelegt würde. Auch vorher Gedanken zu machen und Erfahrungen von Menschen einzubringen, die das seit Jahren/Jahrzehnten bereits machen, ist absolut sinnvoll.

Testaufgaben nach einem Bewerbungsgespräch

Ich habe jetzt länger überlegt, ob ich darüber überhaupt bloggen möchte. Ich mache es doch einmal, denn es gab für mich etwas sehr interessantes und es ist schon eine ganze Weile her.

Ich war auf Jobsuche, schrieb hier und da eine Bewerbung. Dann hatte ich ein Vorstellungsgespräch und der Herr am anderen Ende der Telefonleitung meinte, es könnte passen. Nachdem er über meine Konditionen nachdachte und das mit der Geschäftsleitung durchsprach, bekam ich einen Anruf, dass diese passen würden, die Firma aber eine Testaufgabe für mich hätte. Darum soll es hier gehen, nämlich um diese eine Testaufgabe und um Testaufgaben im Allgemeinen.

Nachdem wir den Techstack abgeklärt hatten und es darum um PHP und Symfony ging und ich auch sagte, dass ich von beidem keine Ahnung habe (PHP habe ich das letzte Mal vor 20 Jahren gemacht), wurde mir versichert, dass vor dem persönlichen Kennenlernen nur noch eine einfache Testaufgabe zu meistern wäre, nämlich die Umsetzung eines Kontonummer-Bankleitzahlen-IBAN-Konverters. Ich sagte: kein Problem, das musste ich auch schon in einem echten Projekt vor einigen Jahren machen, er soll mir die Aufgabe zukommen lassen. Kurze Zeit später war dann das Dokument mit der Testaufgabe da. Fünf vollgeschriebene DinA4-Seiten. Dabei ging es nicht um die Entwicklung eines Konverters, sondern um ein gesamtes Projekt mit etlichen Zwischenstationen.

Ich sollte mich erst einmal in PHP 8.1 einarbeiten. Danach in Symfony 6.1. Um beides richtig zu machen, würde ich schon keine Stunden mehr veranschlagen, sondern eher einige Tage bishin zu wenigen Wochen. Eine Programmiersprache lerne ich zwar schnell, vor allem PHP, bei der ich nicht einmal von ganz vorne einsteigen müsste, dann aber noch ein komplexes Framework, das ist Aufwand.

Zusätzlich dazu sollte ein Login-Verfahren entwickelt werden und eine dazugehörige Website mit Datenbankanbindung (MySQL oder MariaDB). In der Datenbank sollten die bereits zuvor konvertierten Daten tabellarisch dargestellt werden. Jeder Aufruf sollte einen Zähler inkrementieren.

Weiterhin sollten die Daten dann als JSON exportiert werden können.

Dazu gehörte dann die Installation und Konfiguration von Debian 11, die Installation der benötigten Software (spezielle PHP-Version, nicht in APT drin, MySQL oder MariaDB, Symfony und Apache oder NGINX).

Das war der technische Part. Dazu kam dann ein Benutzerhandbuch für den Konverter über Funktionalität und Bedienung. Dann noch eine Dokumentation für das gesamte Deployment durch einen Laien (Installation und Konfiguration Betriebssystem, Installation und Konfiguration Webserver, Installation und Konfiguration Datenbankserver, Installation und Konfiguration PHP, Installation und Konfiguration von Symfony – durch einen Laien!).

Weiterhin sollte das Projekt vorher komplett durchgeplant werden, vermute mit Pflichenheft, war nicht genauer beschrieben und es sollten auch Tests (Unit-Tests, händische Tests) durchgeführt und dokumentiert werden.

Versteht mich bitte nicht falsch: Das alles kann ich, aber rein realistisch, wenn man es vernünftig macht, ist das ein Projekt, das man nicht in einigen Stunden hinbringt, selbst, wenn man PHP und Symfony auf hohem Level beherrscht. Schon alleine am Pflichtenheft schreibt man eine Weile, das Benutzerhandbuch rotzt man auch nicht einfach runter…

Ich lehnte den Job dann mit Begründung ab. Eine Antwort darauf erhielt ich nie.

Unterschiede zwischen Qt und wxWidgets

Qt und wxWidgets sind zwei beliebte Frameworks für die Entwicklung von Benutzeroberflächen, die sich in technischen und Lizenzunterschieden unterscheiden. Technisch gesehen basiert Qt auf einer objektorientierten Architektur mit einem eigenen Meta-Objekt-System (MOC), das Funktionen wie Signale und Slots für die Ereignisbehandlung bietet. Im Gegensatz dazu verwendet wxWidgets eine Wrapper-Architektur, die die nativen APIs der Zielplattform nutzt, was zu Anwendungen führt, die sich stärker an das native Look-and-Feel anpassen. In Bezug auf Programmiersprachen unterstützt Qt hauptsächlich C++, bietet aber auch Bindings für Sprachen wie Python (PyQt/PySide). wxWidgets ist primär für C++ konzipiert, hat aber ebenfalls Bindings für Python (wxPython) und Perl. Beim GUI-Design kommt Qt mit dem leistungsstarken Qt Designer zur visuellen Gestaltung von Benutzeroberflächen, während wxWidgets oft manuelles Codieren der GUI oder den Einsatz von Drittanbieter-Tools erfordert. In Bezug auf die Plattformunterstützung deckt Qt Windows, macOS, Linux sowie Embedded-Systeme und mobile Plattformen (Android, iOS) ab. wxWidgets unterstützt ebenfalls Windows, macOS und Linux, hat aber eingeschränkte Unterstützung für mobile Geräte.

In Bezug auf die Lizenzierung ist Qt unter GPL, LGPL und kommerziellen Lizenzen lizenziert. Die GPL erfordert die Offenlegung des Quellcodes von abgeleiteten Werken, während die LGPL eine flexiblere Nutzung ermöglicht, insbesondere für proprietäre Software, wenn dynamische Verlinkung verwendet wird. Unternehmen können auch eine kommerzielle Lizenz erwerben, um diese Einschränkungen zu umgehen. wxWidgets wird unter der wxWidgets-Lizenz veröffentlicht, die sehr liberal ist und ähnlich wie die LGPL funktioniert. Sie erlaubt die Entwicklung von sowohl Open-Source- als auch proprietärer Software, ohne die Notwendigkeit, den Quellcode offenzulegen.

Zusammenfassung der Unterschiede

  • Architektur:
    • Qt: Objektorientiert mit MOC, Signale und Slots.
    • wxWidgets: Wrapper-Architektur, nutzt native APIs.
  • Programmiersprachen:
    • Qt: Hauptsächlich C++, Bindings für Python und andere.
    • wxWidgets: Primär C++, Bindings für Python und Perl.
  • GUI-Design:
    • Qt: Qt Designer für visuelle Gestaltung.
    • wxWidgets: Oft manuelles Codieren oder Drittanbieter-Tools.
  • Plattformunterstützung:
    • Qt: Windows, macOS, Linux, Embedded, mobile (Android, iOS).
    • wxWidgets: Windows, macOS, Linux, eingeschränkte mobile Unterstützung.
  • Lizenz:
    • Qt: GPL, LGPL, kommerziell.
    • wxWidgets: Liberale wxWidgets-Lizenz, ähnlich LGPL.

wxWidgets-Tutorial 014: Überblick Event-Handling

In diesem Video zeige ich grob, wie das Event-Handling funktioniert. Tiefer gehen wir darauf aber dann bei den einzelnen Widgets ein.

Letztlich gibt es drei Varianten, wovon die dritte „deprecated“ ist und nicht mehr in neuen Programmen benutzt werden soll:

  1. Event-Table
  2. Bind
  3. Connect
Überblick über Event-Handling

Ein Screenshot unseres Beispielprogramms.

Screenshot unseres Beispielprogramms

Der Quelltext:

#include <wx/wx.h>

class MyApp : public wxApp {

	public:
		bool OnInit();

};

class MyFrame : public wxFrame {

	public:
		MyFrame();
	
	protected:
		void OnButtonClick(wxCommandEvent &event);

};

IMPLEMENT_APP(MyApp)

bool MyApp::OnInit() {
	auto *myFrame = new MyFrame;
	myFrame->Show();

	SetTopWindow(myFrame);

	return true;
}

MyFrame::MyFrame() : wxFrame(nullptr, wxID_ANY, _("Events")) {
	wxButton *button = new wxButton(this, wxID_ANY, _("Click me"));

	button->Bind(wxEVT_BUTTON, &MyFrame::OnButtonClick, this);
}

void MyFrame::OnButtonClick(wxCommandEvent &event) {
	std::cout << "Button clicked" << std::endl;
}

Hier geht es zum Video.