<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>markob.de</title><link>https://markob.de/</link><description>Recent content on markob.de</description><generator>Hugo</generator><language>de-DE</language><lastBuildDate>Mon, 31 Aug 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://markob.de/index.xml" rel="self" type="application/rss+xml"/><item><title>LimeSurvey 7.0.11 → 7.0.12</title><link>https://markob.de/limesurvey/releases/7.0.12/</link><pubDate>Mon, 31 Aug 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/releases/7.0.12/</guid><description>&lt;h2 id="kopfdaten"&gt;Kopfdaten und Grenzen&lt;/h2&gt;
&lt;dl class="release-box"&gt;
 &lt;dt&gt;Release&lt;/dt&gt;
 &lt;dd&gt;7.0.11 → 7.0.12&lt;/dd&gt;
 &lt;dt&gt;Commits&lt;/dt&gt;
 &lt;dd&gt;36&lt;/dd&gt;
 &lt;dt&gt;Geänderte Dateien&lt;/dt&gt;
 &lt;dd&gt;170&lt;/dd&gt;
 &lt;dt&gt;Analyse&lt;/dt&gt;
 &lt;dd&gt;2026-09-01&lt;/dd&gt;
 &lt;dt&gt;Schwerpunkt&lt;/dt&gt;
 &lt;dd&gt;Barrierefreiheit und Sicherheit&lt;/dd&gt;
&lt;/dl&gt;
&lt;h3 id="grenzen"&gt;Nicht untersucht&lt;/h3&gt;
&lt;p&gt;Verglichen wurden die Tags &lt;code&gt;7.0.11+260821&lt;/code&gt; vom 20. August 2026 und &lt;code&gt;7.0.12+260833&lt;/code&gt; vom 31. August 2026 mit &lt;code&gt;git log --oneline&lt;/code&gt; und &lt;code&gt;git diff --stat&lt;/code&gt;. Nicht ausgewertet wurden die Übersetzungsdateien unter &lt;code&gt;locale/&lt;/code&gt;, die Inhalte des Verzeichnisses &lt;code&gt;vendor/&lt;/code&gt; über die Versionszeilen der Sperrdatei hinaus sowie die minifizierten Build-Artefakte unter &lt;code&gt;assets/packages/&lt;/code&gt;; Aussagen darüber, ob die ausgelieferten Build-Stände deckungsgleich mit den geänderten Quelldateien sind, bleiben deshalb offen. Indirekte Effekte über transitive Drittabhängigkeiten sind durch reine Diff-Analyse nicht vollständig erfassbar, weil die Sperrdatei nur die unmittelbar gebundenen Stände nennt. Die Kurzliste musste einen Eintrag geringerer Relevanz auslassen: die Umstellung der Gruppen- und Fragenkennungen auf Ganzzahlen in der JSON-Antwort des Fragenbaums.&lt;/p&gt;</description></item><item><title>Das Framework ist nur ein Detail. Das Domainmodell ist es nicht.</title><link>https://markob.de/limesurvey/domain-model/</link><pubDate>Mon, 24 Aug 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/domain-model/</guid><description>&lt;p&gt;In &lt;a href="https://markob.de/limesurvey/yii3"&gt;Das Framework ist nur ein Detail&lt;/a&gt; war unsere These: Neue Anwendungslogik sollte nicht davon abhängen, ob am äußeren Rand Yii, Slim oder ein anderes Framework HTTP-Requests verarbeitet. Das Framework sollte Adapter sein, nicht Architektur.&lt;/p&gt;
&lt;p&gt;Daran hat sich nichts geändert. Inzwischen beschäftigt uns allerdings eine Frage, die noch eine Ebene tiefer geht: Wenn wir das Framework aus dem Zentrum von LimeSurvey entfernen – welches Domainmodell wollen wir dort eigentlich erhalten? Begriffe wie &lt;code&gt;QuestionGroup&lt;/code&gt;, &lt;code&gt;Question&lt;/code&gt;, &lt;code&gt;SubQuestion&lt;/code&gt; oder &lt;code&gt;QuestionType&lt;/code&gt; sind für LimeSurvey-Entwickler so selbstverständlich, dass man leicht vergisst, sie überhaupt noch infrage zu stellen. Aber sind das notwendige Konzepte eines Survey-Systems – oder historische Architekturentscheidungen, die uns heute nur deshalb wie Domainlogik erscheinen, weil LimeSurvey seit vielen Jahren so funktioniert?&lt;/p&gt;</description></item><item><title>Kurs Evaluationen</title><link>https://markob.de/werkstatt/kurs-evaluationen/</link><pubDate>Sat, 22 Aug 2026 00:00:00 +0000</pubDate><guid>https://markob.de/werkstatt/kurs-evaluationen/</guid><description>&lt;p&gt;Wer an einer Hochschule Lehrevaluationen mit LimeSurvey umsetzt, kennt das Muster: Es funktioniert – bis die Struktur komplexer wird. Eine Vorlesung mit drei Übungsgruppen und drei unterschiedlichen Lehrpersonen ist mit LimeSurvey allein kein Survey-Problem mehr, sondern ein Datenmodell-Problem, das man LimeSurvey nicht ansieht.&lt;/p&gt;
&lt;h2 id="das-eigentliche-problem-liegt-vor-der-umfrage"&gt;Das eigentliche Problem liegt vor der Umfrage&lt;/h2&gt;
&lt;p&gt;LimeSurvey ist eine ausgezeichnete Survey Engine: Gruppen, Fragen, Logik, Aktivierung, Teilnehmerverwaltung – das alles beherrscht es zuverlässig. Was LimeSurvey nicht mitbringt, ist ein Modell für die akademische Realität, die vor der Umfrage steht:&lt;/p&gt;</description></item><item><title>Das Framework ist nur ein Detail</title><link>https://markob.de/limesurvey/yii3/</link><pubDate>Fri, 21 Aug 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/yii3/</guid><description>&lt;p&gt;In einer &lt;a href="https://careers.limesurvey.org/jobs/Careers/38813000007296145/Full-Stack-Developer-m-f-d"&gt;LimeSurvey-Stellenanzeige für einen Full-Stack-Developer&lt;/a&gt; (Stand: 20. August 2026) taucht unter „Tech We Use&amp;quot; das „Yii-3 PHP Framework&amp;quot; auf – bemerkenswert, denn der aktuelle LimeSurvey-Core basiert weiterhin auf Yii 1.1. Ob damit der bestehende Core migriert werden soll, ob Yii3 nur für neue Komponenten gedacht ist oder ob lediglich einzelne Yii3-Pakete gemeint sind, wissen wir nicht. Für das Folgende spielt das auch keine große Rolle.&lt;/p&gt;
&lt;p&gt;Denn bevor LimeSurvey entscheidet, welches Framework Yii 1.1 irgendwann ersetzt, lohnt sich eine andere Frage: Warum sollte diese Entscheidung für den Anwendungscode überhaupt von Bedeutung sein?&lt;/p&gt;</description></item><item><title>LimeSurvey 7.0.10 → 7.0.11</title><link>https://markob.de/limesurvey/releases/7.0.11/</link><pubDate>Thu, 20 Aug 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/releases/7.0.11/</guid><description>&lt;h2 id="kopfdaten"&gt;Kopfdaten und Grenzen&lt;/h2&gt;
&lt;dl class="release-box"&gt;
 &lt;dt&gt;Release&lt;/dt&gt;
 &lt;dd&gt;7.0.10 → 7.0.11&lt;/dd&gt;
 &lt;dt&gt;Commits&lt;/dt&gt;
 &lt;dd&gt;23&lt;/dd&gt;
 &lt;dt&gt;Geänderte Dateien&lt;/dt&gt;
 &lt;dd&gt;200&lt;/dd&gt;
 &lt;dt&gt;Analyse&lt;/dt&gt;
 &lt;dd&gt;20.08.2026&lt;/dd&gt;
 &lt;dt&gt;Schwerpunkt&lt;/dt&gt;
 &lt;dd&gt;Barrierefreiheit + Korrekturen&lt;/dd&gt;
&lt;/dl&gt;
&lt;h3 id="grenzen"&gt;Nicht untersucht&lt;/h3&gt;
&lt;p&gt;Verglichen wurden die Tags &lt;code&gt;7.0.10+260813&lt;/code&gt; und &lt;code&gt;7.0.11+260821&lt;/code&gt; mit &lt;code&gt;git log --oneline&lt;/code&gt;, &lt;code&gt;git diff --stat&lt;/code&gt; sowie dateiweisen &lt;code&gt;git show&lt;/code&gt;-Aufrufen je Commit; der Analysestand ist der 20. August 2026. Nicht untersucht wurden das Laufzeitverhalten einer installierten Instanz, die Übersetzungskataloge unterhalb von &lt;code&gt;locale/&lt;/code&gt; und die kompilierten Bundles unterhalb von &lt;code&gt;editor/build/&lt;/code&gt;, deren Inhalt nur als Minifikat vorliegt — Aussagen über tatsächliche Bildschirmausgaben und über die Deckungsgleichheit von Editor-Quellcode und ausgelieferter Fassung bleiben daher offen. Indirekte Effekte über transitive Drittabhängigkeiten sind durch reine Diff-Analyse nicht vollständig erfassbar, weil der Diff nur die Sperrdatei und die eingecheckten Bibliotheksdateien zeigt, nicht deren Zusammenspiel zur Laufzeit. Beide Tag-Namen waren im Repository verifizierbar. Im Kapitel „Weitere relevante Änderungen“ sind drei Einträge geringerer Relevanz nicht aufgeführt: die überarbeitete Sicherheitsrichtlinie in &lt;code&gt;SECURITY.md&lt;/code&gt;, die neu hinzugefügte Metadatendatei &lt;code&gt;publiccode.yml&lt;/code&gt; und die Anpassungen an der CI-Konfiguration samt zugehöriger Testkorrektur.&lt;/p&gt;</description></item><item><title>Zweimal `square()` - Teil 3</title><link>https://markob.de/limesurvey/zweimal-square-teil-3/</link><pubDate>Wed, 19 Aug 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/zweimal-square-teil-3/</guid><description>&lt;p&gt;Im zweiten Teil dieser Geschichte ging es um eine unbequeme Erkenntnis: Zwei zehn Jahre lang getrennt gewachsene Statistics-Implementierungen lassen sich nicht einfach wieder zusammenführen. Ein Diff zeigt, dass sich Admin und Public Statistics unterscheiden – er sagt nicht, ob dieser Unterschied fachlich notwendig ist oder nur historische Drift.&lt;/p&gt;
&lt;p&gt;Also erst verstehen, dann verändern. Characterization Tests, um vorhandenes Verhalten zu dokumentieren. Die versteckte &lt;code&gt;$_POST&lt;/code&gt;-Abhängigkeit sichtbar machen, als ersten kleinen Schritt zu einer Trust Boundary.&lt;/p&gt;</description></item><item><title>Zweimal `square()` - Teil 2</title><link>https://markob.de/limesurvey/zweimal-square-teil-2/</link><pubDate>Tue, 18 Aug 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/zweimal-square-teil-2/</guid><description>&lt;p&gt;Im ersten Teil dieser Geschichte führte uns eine SQL Injection zu zwei Statistics-Helpern, zwei &lt;code&gt;buildSelects()&lt;/code&gt;-Funktionen und schließlich zu zwei Funktionen, die nichts weiter tun, als eine Zahl zu quadrieren.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$number&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$squarenumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$squarenumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$number&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;$number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$squarenumber&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Zweimal.&lt;/p&gt;
&lt;p&gt;Die Git-Historie führte zurück ins Jahr 2016. Für die Public Statistics wurde damals ein großer Teil der bestehenden Statistics-Implementierung abgespalten. Seitdem entwickelten sich Admin Statistics und Public Statistics getrennt weiter – bis eine SQL Injection zehn Jahre später beide Zweige wieder einholte.&lt;/p&gt;</description></item><item><title>Zweimal `square()` - Teil 1</title><link>https://markob.de/limesurvey/zweimal-square-teil-1/</link><pubDate>Mon, 17 Aug 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/zweimal-square-teil-1/</guid><description>&lt;p&gt;Manchmal beginnt Code-Archäologie nicht mit einem spektakulären Fund. Manchmal beginnt sie mit einem SQL-Injection-Fix – und einer Funktion, die eine Zahl quadriert.&lt;/p&gt;
&lt;p&gt;Am 12. August 2026 wurde im LimeSurvey-Repository Pull Request &lt;a href="https://github.com/LimeSurvey/LimeSurvey/pull/5225"&gt;#5225&lt;/a&gt; eröffnet. Der Titel: &amp;ldquo;Fixed issue #20648: [security] SQL injection in statistics&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Das Problem war ernst. In der Statistikfunktion konnten manipulierte Filterparameter dazu führen, dass vom Request stammende Feldnamen ungeprüft in SQL-Abfragen gelangten. Der Fix führte deshalb eine Allowlist ein: Nur Spalten, die tatsächlich im Schema der jeweiligen Response-Tabelle existieren, dürfen noch als Feldnamen verwendet werden&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;</description></item><item><title>Naming ist wichtig</title><link>https://markob.de/limesurvey/naming-ist-wichtig/</link><pubDate>Sat, 15 Aug 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/naming-ist-wichtig/</guid><description>&lt;p&gt;Manchmal reicht ein einzelner Feldname, um zu zeigen, wie viel Architektur eigentlich in einer Namensentscheidung steckt. Ein aktueller Pull Request im LimeSurvey-Kernrepository liefert dafür ein besonders klares Beispiel.&lt;/p&gt;
&lt;h2 id="der-fall"&gt;Der Fall&lt;/h2&gt;
&lt;p&gt;Am 14. August 2026 wurde im LimeSurvey-Repository der Pull Request &lt;a href="https://github.com/LimeSurvey/LimeSurvey/pull/5236"&gt;#5236&lt;/a&gt; eingereicht: ein neues Feature, das Surveys um einen zusätzlichen, sprachunabhängigen Titel erweitert – gedacht als interne Bezeichnung zur Identifikation im Administrationsbereich, unabhängig vom öffentlich sichtbaren, lokalisierten Umfragetitel.&lt;/p&gt;
&lt;p&gt;Technisch ist das ein sinnvolles Feature. Der bestehende Titel einer Survey (&lt;code&gt;survey_languagesettings.surveyls_title&lt;/code&gt;) ist an eine Sprache gebunden und für interne Zwecke – etwa das Wiederfinden einer Umfrage in einer langen Liste – oft ungeeignet. Ein zweites, sprachneutrales Feld schließt eine echte Lücke.&lt;/p&gt;</description></item><item><title>LimeSurvey 7.0.9 → 7.0.10</title><link>https://markob.de/limesurvey/releases/7.0.10/</link><pubDate>Fri, 14 Aug 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/releases/7.0.10/</guid><description>&lt;h2 id="kopfdaten"&gt;Kopfdaten und Grenzen&lt;/h2&gt;
&lt;dl class="release-box"&gt;
 &lt;dt&gt;Release&lt;/dt&gt;
 &lt;dd&gt;7.0.9 → 7.0.10&lt;/dd&gt;
 &lt;dt&gt;Commits&lt;/dt&gt;
 &lt;dd&gt;12&lt;/dd&gt;
 &lt;dt&gt;Geänderte Dateien&lt;/dt&gt;
 &lt;dd&gt;28&lt;/dd&gt;
 &lt;dt&gt;Analyse&lt;/dt&gt;
 &lt;dd&gt;14.08.2026&lt;/dd&gt;
 &lt;dt&gt;Schwerpunkt&lt;/dt&gt;
 &lt;dd&gt;Sicherheit und Datenkorrektheit&lt;/dd&gt;
&lt;/dl&gt;
&lt;h3 id="grenzen"&gt;Nicht untersucht&lt;/h3&gt;
&lt;p&gt;Verglichen wurden die Tags &lt;code&gt;7.0.9+260812&lt;/code&gt; und &lt;code&gt;7.0.10+260813&lt;/code&gt; mit &lt;code&gt;git log --oneline 7.0.9+260812..7.0.10+260813&lt;/code&gt; und &lt;code&gt;git diff --stat 7.0.9+260812..7.0.10+260813&lt;/code&gt;; beide Tags sind im Repository vorhanden. Nicht ausgewertet wurden die binären Übersetzungskataloge unter &lt;code&gt;locale/&lt;/code&gt; und die daraus abgeleitete Vorlagendatei, weshalb keine Aussage darüber möglich ist, ob eine der neuen Übersetzungen bestehende Zeichenketten inhaltlich verschiebt. Es wurde nichts ausgeführt: weder die Testsuite noch ein Update gegen eine reale Datenbank, sodass alle Aussagen über Laufzeitverhalten aus dem Quelltext abgeleitet sind. Indirekte Effekte über transitive Drittabhängigkeiten sind durch reine Diff-Analyse nicht vollständig erfassbar. Ob das offizielle Release-Archiv über den Repository-Stand hinaus Bündel neu baut, ist aus dem Repository nicht bestimmbar. Die Kurzliste musste keine Einträge auslassen.&lt;/p&gt;</description></item><item><title>LimeSurvey 7.0.8 → 7.0.9</title><link>https://markob.de/limesurvey/releases/7.0.9/</link><pubDate>Tue, 11 Aug 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/releases/7.0.9/</guid><description>&lt;h2 id="kopfdaten"&gt;Kopfdaten und Grenzen&lt;/h2&gt;
&lt;dl class="release-box"&gt;
 &lt;dt&gt;Release&lt;/dt&gt;
 &lt;dd&gt;7.0.8 → 7.0.9&lt;/dd&gt;
 &lt;dt&gt;Commits&lt;/dt&gt;
 &lt;dd&gt;25&lt;/dd&gt;
 &lt;dt&gt;Geänderte Dateien&lt;/dt&gt;
 &lt;dd&gt;248&lt;/dd&gt;
 &lt;dt&gt;Analyse&lt;/dt&gt;
 &lt;dd&gt;11.08.2026&lt;/dd&gt;
 &lt;dt&gt;Schwerpunkt&lt;/dt&gt;
 &lt;dd&gt;Sicherheit + Stabilisierung&lt;/dd&gt;
&lt;/dl&gt;
&lt;h3 id="grenzen"&gt;Nicht untersucht&lt;/h3&gt;
&lt;p&gt;Verglichen wurden die Tags &lt;code&gt;7.0.8+260806&lt;/code&gt; und &lt;code&gt;7.0.9+260812&lt;/code&gt;; beide sind im Repository vorhanden und wurden über &lt;code&gt;git log --oneline 7.0.8+260806..7.0.9+260812&lt;/code&gt; und &lt;code&gt;git diff --stat 7.0.8+260806..7.0.9+260812&lt;/code&gt; ausgewertet. Nicht untersucht wurden die Inhalte des Verzeichnisses &lt;code&gt;vendor/&lt;/code&gt;, das den weit überwiegenden Teil der 248 geänderten Dateien ausmacht und dessen Dateien im Diff durchgängig als Binärdateien geführt werden — Aussagen über das Verhalten der aktualisierten Fremdbibliotheken selbst stützen sich daher ausschließlich auf die Metadaten in &lt;code&gt;composer.lock&lt;/code&gt; und nicht auf deren Quelltext. Ebenfalls nicht ausgewertet wurden die Übersetzungsdateien unterhalb von &lt;code&gt;locale/&lt;/code&gt; sowie die Build-Artefakte des React-Editors, weshalb offenbleibt, ob eine Zeichenkettenänderung in einer bestimmten Sprache vollständig nachgezogen ist. Indirekte Effekte über transitive Drittabhängigkeiten sind durch reine Diff-Analyse nicht vollständig erfassbar, insbesondere nicht bei den in diesem Release angehobenen HTTP- und Kryptobibliotheken. Die Kurzliste musste keine Einträge auslassen.&lt;/p&gt;</description></item><item><title>LimeSurvey 7.0.7 → 7.0.8</title><link>https://markob.de/limesurvey/releases/7.0.8/</link><pubDate>Thu, 06 Aug 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/releases/7.0.8/</guid><description>&lt;h2 id="kopfdaten"&gt;Kopfdaten und Grenzen&lt;/h2&gt;
&lt;dl class="release-box"&gt;
 &lt;dt&gt;Release&lt;/dt&gt;
 &lt;dd&gt;7.0.7 → 7.0.8&lt;/dd&gt;
 &lt;dt&gt;Commits&lt;/dt&gt;
 &lt;dd&gt;29&lt;/dd&gt;
 &lt;dt&gt;Geänderte Dateien&lt;/dt&gt;
 &lt;dd&gt;136&lt;/dd&gt;
 &lt;dt&gt;Analyse&lt;/dt&gt;
 &lt;dd&gt;11.08.2026&lt;/dd&gt;
 &lt;dt&gt;Schwerpunkt&lt;/dt&gt;
 &lt;dd&gt;Fehlerbehebungen und Editorarbeiten&lt;/dd&gt;
&lt;/dl&gt;
&lt;h3 id="grenzen"&gt;Nicht untersucht&lt;/h3&gt;
&lt;p&gt;Verglichen wurden die Tags &lt;code&gt;7.0.7+260729&lt;/code&gt; und &lt;code&gt;7.0.8+260806&lt;/code&gt; mit &lt;code&gt;git log --oneline 7.0.7+260729..7.0.8+260806&lt;/code&gt; und &lt;code&gt;git diff --stat 7.0.7+260729..7.0.8+260806&lt;/code&gt;; beide Tags sind im Repository vorhanden und liegen auf dem Zweig &lt;code&gt;master&lt;/code&gt;. Nicht ausgewertet wurden die Übersetzungsdateien unterhalb von &lt;code&gt;locale/&lt;/code&gt;, die kompilierten Bundles unterhalb von &lt;code&gt;editor/build/&lt;/code&gt; sowie die JavaScript-Quellkarten; Aussagen über Zeichenketten in einzelnen Sprachen und über das exakte Laufzeitverhalten der ausgelieferten Bundles bleiben deshalb offen. Die Testdateien unterhalb von &lt;code&gt;tests/&lt;/code&gt; wurden nur daraufhin gesichtet, welche Produktionsänderung sie begleiten, nicht auf ihre Abdeckung hin. Indirekte Effekte über transitive Drittabhängigkeiten sind durch reine Diff-Analyse nicht vollständig erfassbar, weil der Diff nur die im Repository eingecheckten Paketstände zeigt und nicht das Verhalten der Pakete untereinander. Aus dem Kapitel „Weitere relevante Änderungen&amp;quot; ist ein Eintrag geringerer Relevanz weggelassen, weil er sich keinem der sieben vorgegebenen Bereiche zuordnen ließ: die geänderte Fehlermeldung der Anmeldung bei abgelaufenem Benutzerkonto.&lt;/p&gt;</description></item><item><title>Von KleinSite nach Hugo</title><link>https://markob.de/werkstatt/hugo/</link><pubDate>Thu, 06 Aug 2026 00:00:00 +0000</pubDate><guid>https://markob.de/werkstatt/hugo/</guid><description>&lt;p&gt;Als ich vor einiger Zeit KleinSite gebaut habe – eine schlanke, dateibasierte Content-Engine, die Markdown und Twig-Templates verarbeitet – war das genau das, was ich brauchte: kein CMS-Overhead, volle Kontrolle, schnell gebaut. Für eine Handvoll Artikel funktionierte das gut. Aber irgendwann kippt jedes selbstgebaute System von &amp;ldquo;praktisch&amp;rdquo; zu &amp;ldquo;Baustelle&amp;rdquo;, und genau da war ich mit KleinSite angekommen.&lt;/p&gt;
&lt;h2 id="der-eigentliche-auslöser-war-keine-technische-grenze"&gt;Der eigentliche Auslöser war keine technische Grenze&lt;/h2&gt;
&lt;p&gt;Man könnte die Geschichte technisch erzählen: KleinSite konnte dies nicht, jenes nicht, also musste ein Wechsel her. Das wäre aber nicht ehrlich. Die eigentliche Frage war eine andere: Will ich meine Zeit in die Pflege einer eigenen Content-Engine stecken – oder in Content selbst?&lt;/p&gt;</description></item><item><title>Die sechs Etappen erfolgreicher KI-Softwareentwicklung</title><link>https://markob.de/werkstatt/ki-leitfaden/</link><pubDate>Sat, 01 Aug 2026 00:00:00 +0000</pubDate><guid>https://markob.de/werkstatt/ki-leitfaden/</guid><description>&lt;p&gt;Noch nie war es so einfach, Software zu entwickeln – und gleichzeitig so leicht, ein Projekt in eine falsche Richtung laufen zu lassen. Moderne Coding Agents erzeugen in wenigen Minuten Hunderte Zeilen Code. Was sie jedoch nicht ersetzen, ist ein gemeinsames Verständnis davon, was überhaupt gebaut werden soll.&lt;/p&gt;
&lt;p&gt;Ein Coding Agent kann eine Aufgabe brillant lösen – aber nur die Aufgabe, die er kennt. Was er nicht kennt, entscheidet er selbst, plausibel und konsequent, und oft an drei verschiedenen Stellen unterschiedlich. Das Ergebnis sieht dann nicht nach schlechter Arbeit aus. Es sieht nach drei verschiedenen Meinungen darüber aus, was das Produkt eigentlich ist.&lt;/p&gt;</description></item><item><title>LimeSurvey 7.0.6 → 7.0.7</title><link>https://markob.de/limesurvey/releases/7.0.7/</link><pubDate>Tue, 28 Jul 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/releases/7.0.7/</guid><description>&lt;h2 id="kopfdaten"&gt;Kopfdaten und Grenzen&lt;/h2&gt;
&lt;dl class="release-box"&gt;
 &lt;dt&gt;Release&lt;/dt&gt;
 &lt;dd&gt;7.0.6 → 7.0.7&lt;/dd&gt;
 &lt;dt&gt;Commits&lt;/dt&gt;
 &lt;dd&gt;14&lt;/dd&gt;
 &lt;dt&gt;Geänderte Dateien&lt;/dt&gt;
 &lt;dd&gt;64&lt;/dd&gt;
 &lt;dt&gt;Analyse&lt;/dt&gt;
 &lt;dd&gt;10.08.2026&lt;/dd&gt;
 &lt;dt&gt;Schwerpunkt&lt;/dt&gt;
 &lt;dd&gt;Editorumstellung und Massenaktionen&lt;/dd&gt;
&lt;/dl&gt;
&lt;h3 id="grenzen"&gt;Nicht untersucht&lt;/h3&gt;
&lt;p&gt;Verglichen wurden die im lokalen Repository verifizierten Tags &lt;code&gt;7.0.6+260722&lt;/code&gt; (22.07.2026) und &lt;code&gt;7.0.7+260729&lt;/code&gt; (28.07.2026) mit &lt;code&gt;git log --oneline 7.0.6+260722..7.0.7+260729&lt;/code&gt; und &lt;code&gt;git diff --stat 7.0.6+260722..7.0.7+260729&lt;/code&gt;. Nicht ausgewertet wurden die kompilierten Editor-Bundles unter &lt;code&gt;editor/build/static/js&lt;/code&gt;, die minifizierten Stylesheets des Adminthemes sowie die binären Übersetzungskataloge und die Vorlagendatei der Übersetzungen. Dadurch bleibt offen, ob die Umstellung des Editors auf die Voreinstellung über die zitierten Quelldateien hinaus weitere Verhaltensänderungen im ausgelieferten Bundle mitbringt. Indirekte Effekte über transitive Drittabhängigkeiten lassen sich durch reine Diff-Analyse nicht vollständig erfassen. Aus dem Kapitel „Weitere relevante Änderungen&amp;quot; wurden zwei Einträge geringerer Relevanz weggelassen, nämlich die Stilanpassung der Blätterschaltflächen im Editor und die neu hinzugefügten Modultests für das Anlegen und Duplizieren von Fragengruppen.&lt;/p&gt;</description></item><item><title>LimeSurvey 7.0.5 → 7.0.6</title><link>https://markob.de/limesurvey/releases/7.0.6/</link><pubDate>Wed, 22 Jul 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/releases/7.0.6/</guid><description>&lt;h2 id="kopfdaten"&gt;Kopfdaten und Grenzen&lt;/h2&gt;
&lt;dl class="release-box"&gt;
 &lt;dt&gt;Release&lt;/dt&gt;
 &lt;dd&gt;7.0.5 → 7.0.6&lt;/dd&gt;
 &lt;dt&gt;Commits&lt;/dt&gt;
 &lt;dd&gt;64&lt;/dd&gt;
 &lt;dt&gt;Geänderte Dateien&lt;/dt&gt;
 &lt;dd&gt;1083&lt;/dd&gt;
 &lt;dt&gt;Analyse&lt;/dt&gt;
 &lt;dd&gt;10.08.2026&lt;/dd&gt;
 &lt;dt&gt;Schwerpunkt&lt;/dt&gt;
 &lt;dd&gt;Ranking-Datenmodell, Editorausbau, Abhängigkeiten&lt;/dd&gt;
&lt;/dl&gt;
&lt;h3 id="grenzen"&gt;Nicht untersucht&lt;/h3&gt;
&lt;p&gt;Verglichen wurden die im lokalen Repository verifizierten Tags &lt;code&gt;7.0.5+260623&lt;/code&gt; (23.06.2026) und &lt;code&gt;7.0.6+260722&lt;/code&gt; (&lt;br&gt;
22.07.2026) mit &lt;code&gt;git log --oneline 7.0.5+260623..7.0.6+260722&lt;/code&gt; und &lt;code&gt;git diff --shortstat 7.0.5+260623..7.0.6+260722&lt;/code&gt;.&lt;br&gt;
Nicht ausgewertet wurden der Inhalt des mitgelieferten &lt;code&gt;vendor/&lt;/code&gt;-Baums (837 der 1083 geänderten Dateien), die kompilierten Bundles unter &lt;code&gt;editor/build/&lt;/code&gt; und &lt;code&gt;assets/packages/*/build&lt;/code&gt;, die minifizierten Admin-Theme-Stylesheets sowie die Übersetzungsdateien. Dadurch bleibt offen, ob die Umstellung der Tabellenkalkulations-Bibliothek und der Sprung des DI-Containers über die zitierten Quelldateien hinaus weitere Verhaltensänderungen mitbringen. Indirekte Effekte über transitive Drittabhängigkeiten lassen sich durch reine Diff-Analyse nicht vollständig erfassen. Aus dem Kapitel „Weitere relevante Änderungen&amp;quot; wurden neun Einträge geringerer Relevanz weggelassen, darunter der Wegfall obsoleter PHP-Versionsprüfungen, die Feldnamen-Ersetzung beim Gruppenimport, der Nullwert-Umgang im SPSS-Export und der Identity-Insert-Umgang bei der Wiederherstellung archivierter Antworten unter SQL Server.&lt;/p&gt;</description></item><item><title>Joomla 1.0: Überraschend moderne Ideen unter 20 Jahren PHP</title><link>https://markob.de/werkstatt/joomla/</link><pubDate>Tue, 07 Jul 2026 00:00:00 +0000</pubDate><guid>https://markob.de/werkstatt/joomla/</guid><description>&lt;p&gt;Vor ein paar Tagen habe ich aus reiner Neugier das GitHub-Archiv von Joomla 1.0 geöffnet. Nicht das aktuelle Joomla – das wird seit Jahren aktiv weiterentwickelt und hat mit der Version von 2005 kaum noch etwas gemeinsam. Eigentlich wollte ich nur wissen, wie sich ein CMS anfühlt, das mich vor über zwanzig Jahren begeistert hat. Am Ende blieb ich deutlich länger hängen als geplant.&lt;/p&gt;
&lt;p&gt;Die ursprüngliche Idee war sogar, ob sich das mit vertretbarem Aufwand auf PHP 8.3 heben ließe. Der Gedanke war schnell wieder verworfen. Aber der Blick in den Code hat sich trotzdem gelohnt – nicht wegen der Nostalgie, sondern wegen dem, was er über 20 Jahre PHP-Entwicklung erzählt.&lt;/p&gt;</description></item><item><title>Report-driven Survey Design</title><link>https://markob.de/limesurvey/report-driven-survey-design/</link><pubDate>Sat, 27 Jun 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/report-driven-survey-design/</guid><description>&lt;p&gt;Ich wollte eine Treiberanalyse bauen. Dafür brauchte ich eine Matrixfrage – mehrere Aspekte als Subquestions, einheitliche Skala. Dazu eine separate Gesamtbewertung als Zielgröße. Erst nachdem diese Struktur stand, habe ich überlegt, welche Aspekte ich überhaupt abfragen wollte.&lt;/p&gt;
&lt;p&gt;Irgendwann fiel mir auf:&lt;/p&gt;
&lt;p&gt;Ich entwerfe gar keine Umfragen mehr. Ich entwerfe Reports.&lt;/p&gt;
&lt;h2 id="das-problem-mit-der-klassischen-reihenfolge"&gt;Das Problem mit der klassischen Reihenfolge&lt;/h2&gt;
&lt;p&gt;Der übliche Weg beim Fragebogendesign: Was wollen wir wissen? Welche Fragen stellen wir? Welcher Fragetyp passt? Der Report kommt am Ende – als Auswertung dessen, was die Daten hergeben.&lt;/p&gt;</description></item><item><title>LimeSurvey 7.0.4 → 7.0.5</title><link>https://markob.de/limesurvey/releases/7.0.5/</link><pubDate>Tue, 23 Jun 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/releases/7.0.5/</guid><description>&lt;h2 id="kopfdaten"&gt;Kopfdaten und Grenzen&lt;/h2&gt;
&lt;dl class="release-box"&gt;
 &lt;dt&gt;Release&lt;/dt&gt;
 &lt;dd&gt;7.0.4 → 7.0.5&lt;/dd&gt;
 &lt;dt&gt;Commits&lt;/dt&gt;
 &lt;dd&gt;11&lt;/dd&gt;
 &lt;dt&gt;Geänderte Dateien&lt;/dt&gt;
 &lt;dd&gt;50&lt;/dd&gt;
 &lt;dt&gt;Analyse&lt;/dt&gt;
 &lt;dd&gt;11.08.2026&lt;/dd&gt;
 &lt;dt&gt;Schwerpunkt&lt;/dt&gt;
 &lt;dd&gt;Berechtigungsfix und Oberflächenkorrekturen&lt;/dd&gt;
&lt;/dl&gt;
&lt;h3 id="grenzen"&gt;Nicht untersucht&lt;/h3&gt;
&lt;p&gt;Verglichen wurden die Tags &lt;code&gt;7.0.4+260620&lt;/code&gt; und &lt;code&gt;7.0.5+260623&lt;/code&gt; mit &lt;code&gt;git log --oneline 7.0.4+260620..7.0.5+260623&lt;/code&gt;, &lt;code&gt;git diff --stat 7.0.4+260620..7.0.5+260623&lt;/code&gt; sowie dateiweisen Diffs; beide Tags sind im Repository vorhanden und mussten nicht ersetzt werden. Nicht ausgewertet wurden die binären Übersetzungskataloge unter &lt;code&gt;locale/&lt;/code&gt; und die Vorlagendatei &lt;code&gt;locale/_template/limesurvey.pot&lt;/code&gt;, sodass über inhaltliche Änderungen an Oberflächentexten keine Aussage getroffen wird. Ebenfalls nicht auf Auswirkungen untersucht wurden die Änderungen an der Testinfrastruktur unter &lt;code&gt;tests/&lt;/code&gt;, weil dieser Code in einer Produktivinstallation nicht ausgeführt wird; ob die dortige Anmeldelogik nach der Umstellung noch fehlerfrei arbeitet, bleibt damit offen. Die ausgelieferten JavaScript-Bündel wurden nur über den Vergleich ihrer Dateiinhalte und der inhaltsabhängigen Dateinamen geprüft, nicht durch einen eigenen Build. Für die Kurzliste mussten keine Einträge wegen der Höchstzahl entfallen. Indirekte Effekte über transitive Drittabhängigkeiten sind durch reine Diff-Analyse grundsätzlich nicht vollständig erfassbar.&lt;/p&gt;</description></item><item><title>Warum Vergütung auf Platz 7 landet</title><link>https://markob.de/limesurvey/priority-score/</link><pubDate>Tue, 23 Jun 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/priority-score/</guid><description>&lt;p&gt;In einer Employee Retention Survey hat Vergütung &amp;amp; Benefits den größten Gap zum Zielwert. Score 2,6, Zielwert 4,2 – eine Lücke von 1,6 Punkten. Kein anderer Bereich liegt weiter vom Ziel entfernt.&lt;/p&gt;
&lt;p&gt;Trotzdem landet Vergütung auf Platz 7 von 8.&lt;/p&gt;
&lt;p&gt;Das ist kein Fehler. Es ist das Ergebnis einer bewussten Designentscheidung: nicht die Größe der Lücke allein bestimmt die Priorität, sondern die Lücke gewichtet nach strategischer Relevanz.&lt;/p&gt;
&lt;h2 id="das-problem-mit-dem-rohen-gap"&gt;Das Problem mit dem rohen Gap&lt;/h2&gt;
&lt;p&gt;Wer acht Dimensionen einer Mitarbeiterbefragung nach dem Gap zum Zielwert sortiert, bekommt eine Liste. Führung mit Score 2,8 liegt 1,4 Punkte unter dem Ziel. Vergütung mit Score 2,6 liegt 1,6 Punkte darunter. Vergütung hätte also Priorität.&lt;/p&gt;</description></item><item><title>Wo eine Verbesserung die meisten Menschen erreicht</title><link>https://markob.de/limesurvey/ipot-score/</link><pubDate>Tue, 23 Jun 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/ipot-score/</guid><description>&lt;p&gt;&lt;a href="https://markob.de/priority-score"&gt;Im vorigen Artikel&lt;/a&gt; wurde gezeigt warum Vergütung trotz des größten Gaps auf Platz 7 landet: der Priority Score gewichtet nach strategischer Bedeutung, nicht nach Lückengröße. Führung mit 18 % Gewicht schlägt Vergütung mit 5 %.&lt;/p&gt;
&lt;p&gt;Aber der Priority Score hat einen blinden Fleck.&lt;/p&gt;
&lt;p&gt;Er fragt nicht: wie viele Mitarbeitende betrifft das Problem überhaupt?&lt;/p&gt;
&lt;h2 id="was-pri-nicht-sieht"&gt;Was PRI nicht sieht&lt;/h2&gt;
&lt;p&gt;Nehmen wir zwei Treiber aus dem Beispiel:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Treiber&lt;/th&gt;
 &lt;th&gt;Score&lt;/th&gt;
 &lt;th&gt;Gap&lt;/th&gt;
 &lt;th&gt;Gewicht&lt;/th&gt;
 &lt;th&gt;PRI&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Führung&lt;/td&gt;
 &lt;td&gt;2,8&lt;/td&gt;
 &lt;td&gt;1,4&lt;/td&gt;
 &lt;td&gt;18 %&lt;/td&gt;
 &lt;td&gt;0,252&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Vergütung&lt;/td&gt;
 &lt;td&gt;2,6&lt;/td&gt;
 &lt;td&gt;1,6&lt;/td&gt;
 &lt;td&gt;5 %&lt;/td&gt;
 &lt;td&gt;0,080&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;PRI sagt: Führung zuerst. Das Modell argumentiert dass Führung strategisch wichtiger ist als Vergütung – und das stimmt.&lt;/p&gt;</description></item><item><title>LimeSurvey 7.0.3 → 7.0.4</title><link>https://markob.de/limesurvey/releases/7.0.4/</link><pubDate>Sat, 20 Jun 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/releases/7.0.4/</guid><description>&lt;h2 id="kopfdaten"&gt;Kopfdaten und Grenzen&lt;/h2&gt;
&lt;dl class="release-box"&gt;
 &lt;dt&gt;Release&lt;/dt&gt;
 &lt;dd&gt;7.0.3 → 7.0.4&lt;/dd&gt;
 &lt;dt&gt;Commits&lt;/dt&gt;
 &lt;dd&gt;6&lt;/dd&gt;
 &lt;dt&gt;Geänderte Dateien&lt;/dt&gt;
 &lt;dd&gt;12&lt;/dd&gt;
 &lt;dt&gt;Analyse&lt;/dt&gt;
 &lt;dd&gt;11.08.2026&lt;/dd&gt;
 &lt;dt&gt;Schwerpunkt&lt;/dt&gt;
 &lt;dd&gt;Integritätsprüfung + Migrationsfix&lt;/dd&gt;
&lt;/dl&gt;
&lt;h3 id="grenzen"&gt;Nicht untersucht&lt;/h3&gt;
&lt;p&gt;Verglichen wurden die Tags &lt;code&gt;7.0.3+260618&lt;/code&gt; und &lt;code&gt;7.0.4+260620&lt;/code&gt; mittels &lt;code&gt;git log --oneline 7.0.3+260618..7.0.4+260620&lt;/code&gt; und &lt;code&gt;git diff --stat 7.0.3+260618..7.0.4+260620&lt;/code&gt;; beide Tags sind im Repository vorhanden. Nicht ausgewertet wurde der Commit „Dev Automatic translation update&amp;quot; und die davon betroffene Datei &lt;code&gt;locale/_template/limesurvey.pot&lt;/code&gt;, weshalb keine Aussage darüber möglich ist, ob einzelne Oberflächentexte über die hier beschriebenen hinaus ihre Bedeutung geändert haben. Ebenfalls nicht ausgewertet wurden die minifizierten Stylesheets &lt;code&gt;themes/admin/Sea_Green/css/sea_green.min.css&lt;/code&gt; und &lt;code&gt;themes/admin/Sea_Green/css/sea_green-rtl.min.css&lt;/code&gt;, da sie aus den ebenfalls im Diff enthaltenen Quelldateien erzeugt werden. Die Laufzeitwirkung der neuen Integritätsprüfungen wurde nicht in einer Installation nachvollzogen, sondern ausschließlich aus dem Quellcode abgeleitet. Indirekte Effekte über transitive Drittabhängigkeiten sind durch reine Diff-Analyse nicht vollständig erfassbar. Einträge der Kurzliste mussten nicht ausgelassen werden.&lt;/p&gt;</description></item><item><title>Der NPS ist keine Zahl</title><link>https://markob.de/limesurvey/net-promoter-score/</link><pubDate>Fri, 19 Jun 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/net-promoter-score/</guid><description>&lt;p&gt;NPS = 32. Gut oder schlecht?&lt;/p&gt;
&lt;p&gt;Die Frage klingt sinnvoll. Sie ist es nicht – zumindest nicht so gestellt.&lt;/p&gt;
&lt;p&gt;Ein Net Promoter Score ist mehr als eine Kennzahl im klassischen Sinne. Er ist eine verdichtete Verteilung. Hinter jedem NPS-Wert stecken drei Gruppen: Promotoren (Wertung 9–10), Passive (7–8) und Kritiker (0–6). Aus deren Anteilen ergibt sich die Formel:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;NPS = % Promotoren − % Kritiker
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Zwei völlig unterschiedliche Verteilungen können deshalb exakt denselben NPS erzeugen.&lt;/p&gt;</description></item><item><title>Likert-Skalen richtig einsetzen und auswerten</title><link>https://markob.de/limesurvey/likert-skalen/</link><pubDate>Fri, 19 Jun 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/likert-skalen/</guid><description>&lt;p&gt;Wer eine Umfrage baut, kommt an Likert-Skalen kaum vorbei. Zustimmung zu einer Aussage von 1 bis 5, Zufriedenheit von „sehr unzufrieden&amp;quot; bis „sehr zufrieden&amp;quot;, Wichtigkeit von „unwichtig&amp;quot; bis „sehr wichtig&amp;quot; – das Grundprinzip ist immer dasselbe. Und doch entstehen bei der Umsetzung und Auswertung immer wieder dieselben Fehler.&lt;/p&gt;
&lt;p&gt;Dieser Artikel ist kein Statistik-Lehrbuch. Er beantwortet die Fragen, die sich beim Bauen und Interpretieren von Umfragen tatsächlich stellen.&lt;/p&gt;
&lt;h2 id="das-schulnotenproblem"&gt;Das Schulnotenproblem&lt;/h2&gt;
&lt;p&gt;Beginnen wir mit dem häufigsten Missverständnis.&lt;/p&gt;</description></item><item><title>LimeSurvey 7.0.2 → 7.0.3</title><link>https://markob.de/limesurvey/releases/7.0.3/</link><pubDate>Thu, 18 Jun 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/releases/7.0.3/</guid><description>&lt;h2 id="kopfdaten"&gt;Kopfdaten und Grenzen&lt;/h2&gt;
&lt;dl class="release-box"&gt;
 &lt;dt&gt;Release&lt;/dt&gt;
 &lt;dd&gt;7.0.2 → 7.0.3&lt;/dd&gt;
 &lt;dt&gt;Commits&lt;/dt&gt;
 &lt;dd&gt;7&lt;/dd&gt;
 &lt;dt&gt;Geänderte Dateien&lt;/dt&gt;
 &lt;dd&gt;21&lt;/dd&gt;
 &lt;dt&gt;Analyse&lt;/dt&gt;
 &lt;dd&gt;11.08.2026&lt;/dd&gt;
 &lt;dt&gt;Schwerpunkt&lt;/dt&gt;
 &lt;dd&gt;Sicherheitsfix und Datumskorrektur&lt;/dd&gt;
&lt;/dl&gt;
&lt;h3 id="grenzen"&gt;Nicht untersucht&lt;/h3&gt;
&lt;p&gt;Verglichen wurden die Tags &lt;code&gt;7.0.2+260617&lt;/code&gt; (Commit vom 2026-06-16) und &lt;code&gt;7.0.3+260618&lt;/code&gt; (Commit vom 2026-06-17) mit &lt;code&gt;git log --oneline 7.0.2+260617..7.0.3+260618&lt;/code&gt; und &lt;code&gt;git diff --stat 7.0.2+260617..7.0.3+260618&lt;/code&gt;; beide Tags waren im Repository vorhanden. Nicht inhaltlich ausgewertet wurden die vier binären Katalogdateien &lt;code&gt;locale/de/de.mo&lt;/code&gt;, &lt;code&gt;locale/de-informal/de-informal.mo&lt;/code&gt;, &lt;code&gt;locale/it/it.mo&lt;/code&gt; und &lt;code&gt;locale/it-informal/it-informal.mo&lt;/code&gt; sowie die Änderungen an &lt;code&gt;locale/_template/limesurvey.pot&lt;/code&gt;; die beiden Übersetzungs-Commits sind damit nur als vorhanden vermerkt, und ob dabei Texte entfallen sind, bleibt offen. Ebenfalls nicht herangezogen wurden Laufzeitumgebung, Testsuite und die externen Vorgangsnummern AT-2090, AT-2084 und #20565, weshalb Aussagen über Ausnutzbarkeit in einer konkreten Installation und über den Umfang der zugehörigen Vorgänge offenbleiben. Indirekte Effekte über transitive Drittabhängigkeiten sind durch reine Diff-Analyse nicht vollständig erfassbar. Die Kurzliste lässt keine Einträge aus.&lt;/p&gt;</description></item><item><title>LimeSurvey 7.0.1 → 7.0.2</title><link>https://markob.de/limesurvey/releases/7.0.2/</link><pubDate>Wed, 17 Jun 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/releases/7.0.2/</guid><description>&lt;h2 id="kopfdaten"&gt;Kopfdaten und Grenzen&lt;/h2&gt;
&lt;dl class="release-box"&gt;
 &lt;dt&gt;Release&lt;/dt&gt;
 &lt;dd&gt;7.0.1 → 7.0.2&lt;/dd&gt;
 &lt;dt&gt;Commits&lt;/dt&gt;
 &lt;dd&gt;27&lt;/dd&gt;
 &lt;dt&gt;Geänderte Dateien&lt;/dt&gt;
 &lt;dd&gt;687&lt;/dd&gt;
 &lt;dt&gt;Analyse&lt;/dt&gt;
 &lt;dd&gt;11.08.2026&lt;/dd&gt;
 &lt;dt&gt;Schwerpunkt&lt;/dt&gt;
 &lt;dd&gt;Barrierefreiheit und Stabilisierung&lt;/dd&gt;
&lt;/dl&gt;
&lt;h3 id="grenzen"&gt;Nicht untersucht&lt;/h3&gt;
&lt;p&gt;Verglichen wurden die Tags &lt;code&gt;7.0.1+260611&lt;/code&gt; mit Commit-Datum 10. Juni 2026 und &lt;code&gt;7.0.2+260617&lt;/code&gt; mit Commit-Datum 16. Juni 2026 mit den Befehlen &lt;code&gt;git log --oneline 7.0.1+260611..7.0.2+260617&lt;/code&gt; und &lt;code&gt;git diff --stat 7.0.1+260611..7.0.2+260617&lt;/code&gt;; beide Tags sind im Repository vorhanden. Nicht ausgewertet wurden die minifizierten Ableitungen der geänderten Quelldateien, die Sprachdateien unter &lt;code&gt;locale&lt;/code&gt;, der kompilierte React-Build unter &lt;code&gt;editor/build&lt;/code&gt; sowie der Bundle-Inhalt der aktualisierten Pakete unter &lt;code&gt;node_modules&lt;/code&gt; jenseits ihrer Versionsangaben; damit bleibt offen, ob diese Bundles Verhaltensänderungen enthalten, die über die hier beschriebenen hinausgehen. Indirekte Effekte über transitive Drittabhängigkeiten sind durch eine reine Diff-Analyse nicht vollständig erfassbar. Aus dem Kapitel „Weitere relevante Änderungen&amp;quot; wurden keine Einträge ausgelassen.&lt;/p&gt;</description></item><item><title>Treiberanalyse: Welche Frage wirklich zählt</title><link>https://markob.de/limesurvey/treiberanalyse/</link><pubDate>Wed, 17 Jun 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/treiberanalyse/</guid><description>&lt;p&gt;Eine Mitarbeiterbefragung mit zwanzig Zufriedenheitsfragen liefert zwanzig Balkendiagramme. Frage 7 schneidet schlecht ab, Frage 14 hervorragend, der Rest irgendwo dazwischen. Was macht man mit dieser Liste?&lt;/p&gt;
&lt;p&gt;Die naheliegende Reaktion ist: an den schlechtesten Werten ansetzen. Frage 7 verbessern, weil sie am schlechtesten bewertet wurde.&lt;/p&gt;
&lt;p&gt;Das ist oft die falsche Priorität.&lt;/p&gt;
&lt;h2 id="das-problem-mit-reiner-bewertung"&gt;Das Problem mit reiner Bewertung&lt;/h2&gt;
&lt;p&gt;Eine niedrig bewertete Frage ist nicht automatisch ein Problem das sich zu lösen lohnt. Es kommt darauf an, ob diese Frage überhaupt etwas bewegt.&lt;/p&gt;</description></item><item><title>Faker: Reproduzierbare Testdaten für LimeSurvey</title><link>https://markob.de/limesurvey/faker/</link><pubDate>Tue, 16 Jun 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/faker/</guid><description>&lt;p&gt;Eine Umfrage ist fertig konzipiert, aber noch nicht live. Trotzdem soll bereits ein Report dafür entstehen – Trendcharts, KPI-Karten, Segmentierungen. Die Frage die sich sofort stellt: woher kommen die Daten, an denen man das alles testet?&lt;/p&gt;
&lt;p&gt;Die ehrliche Antwort war bei mir lange Zeit: ich habe sie von Hand erzeugt. Umfrage öffnen, durchklicken, Antworten setzen, abschicken. Wieder von vorne. Zwanzig, dreißig, manchmal fünfzig Mal – je nachdem wie überzeugend die Demo aussehen sollte.&lt;/p&gt;</description></item><item><title>Wann ist eine Software „stable"?</title><link>https://markob.de/software-engineering/wann-ist-eine-software-stable/</link><pubDate>Tue, 16 Jun 2026 00:00:00 +0000</pubDate><guid>https://markob.de/software-engineering/wann-ist-eine-software-stable/</guid><description>&lt;p&gt;„Stable&amp;quot; klingt nach einer geprüften Eigenschaft. Tatsächlich ist es meist nur eine Selbstauskunft der Maintainer – keine Aussage über Qualität, sondern eine Behauptung über den eigenen Code.&lt;/p&gt;
&lt;p&gt;Das wird besonders deutlich an einer unauffälligen Composer-Einstellung, die in fast jeder &lt;code&gt;composer.json&lt;/code&gt; steht:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;minimum-stability&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;stable&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Composer unterscheidet Versionen nach einem reinen Namensschema:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;1.0.0-alpha
1.0.0-beta
1.0.0-RC1
1.0.0
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;„Stable&amp;quot; bedeutet hier: kein Alpha, kein Beta, kein Release Candidate. Jede Version ohne einen solchen Suffix gilt als stabil – &lt;code&gt;v1.0.0&lt;/code&gt;, &lt;code&gt;v1.2.3&lt;/code&gt;, &lt;code&gt;v2.0.0&lt;/code&gt;, alle gleichermaßen. Composer trifft damit keine Aussage über Qualität. Es trifft eine Aussage über eine Zeichenkette im Versionsnamen.&lt;/p&gt;</description></item><item><title>Survey as Code: Umfragen versionieren, reviewen und wiederverwenden</title><link>https://markob.de/limesurvey/survey-as-code/</link><pubDate>Mon, 15 Jun 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/survey-as-code/</guid><description>&lt;p&gt;&lt;em&gt;Früher war ich Software-Entwickler, heute bin ich Survey-Entwickler.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Als Software-Entwickler schreibe ich Code. Ich committe ihn, ich reviewe ihn, ich rolle ihn zurück wenn etwas schiefgeht. Jede Änderung hat eine Historie. Jede Funktion lässt sich wiederverwenden.&lt;/p&gt;
&lt;p&gt;Als Survey-Entwickler klicke ich Dropdown-Menüs.&lt;/p&gt;
&lt;p&gt;Das war zumindest bis vor kurzem so.&lt;/p&gt;
&lt;h2 id="das-problem-mit-dem-klicken"&gt;Das Problem mit dem Klicken&lt;/h2&gt;
&lt;p&gt;Eine LimeSurvey-Umfrage entsteht klassisch im Browser. Frage anlegen, Antwortoptionen eintippen, Fragengruppe verschieben, Bedingung setzen. Das funktioniert – bis die Umfrage zum zweiten Mal gebraucht wird.&lt;/p&gt;</description></item><item><title>LimeSurvey 7.0.0 → 7.0.1</title><link>https://markob.de/limesurvey/releases/7.0.1/</link><pubDate>Thu, 11 Jun 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/releases/7.0.1/</guid><description>&lt;h2 id="kopfdaten"&gt;Kopfdaten und Grenzen&lt;/h2&gt;
&lt;dl class="release-box"&gt;
 &lt;dt&gt;Release&lt;/dt&gt;
 &lt;dd&gt;7.0.0 → 7.0.1&lt;/dd&gt;
 &lt;dt&gt;Commits&lt;/dt&gt;
 &lt;dd&gt;140&lt;/dd&gt;
 &lt;dt&gt;Geänderte Dateien&lt;/dt&gt;
 &lt;dd&gt;886&lt;/dd&gt;
 &lt;dt&gt;Analyse&lt;/dt&gt;
 &lt;dd&gt;11.08.2026&lt;/dd&gt;
 &lt;dt&gt;Schwerpunkt&lt;/dt&gt;
 &lt;dd&gt;Sicherheit und Barrierefreiheit&lt;/dd&gt;
&lt;/dl&gt;
&lt;h3 id="grenzen"&gt;Nicht untersucht&lt;/h3&gt;
&lt;p&gt;Verglichen wurden die im lokalen Repository verifizierten Tags &lt;code&gt;7.0.0+260526&lt;/code&gt; (26.05.2026) und &lt;code&gt;7.0.1+260611&lt;/code&gt; (10.06.2026) mit &lt;code&gt;git log --oneline 7.0.0+260526..7.0.1+260611&lt;/code&gt; und &lt;code&gt;git diff --stat 7.0.0+260526..7.0.1+260611&lt;/code&gt;. Nicht ausgewertet wurden der Inhalt des mitgelieferten &lt;code&gt;vendor/&lt;/code&gt;-Baums, die kompilierten Bundles unter &lt;code&gt;assets/packages/*/build&lt;/code&gt; und &lt;code&gt;editor/build&lt;/code&gt;, die minifizierten Stylesheets der Adminthemes sowie die Übersetzungskataloge. Dadurch bleibt offen, ob der Austausch der Vorlagen-Bibliothek und der Umbau der Seitenleisten über die zitierten Quelldateien hinaus weitere Verhaltensänderungen mitbringen. Indirekte Effekte über transitive Drittabhängigkeiten lassen sich durch reine Diff-Analyse nicht vollständig erfassen. Aus dem Kapitel „Weitere relevante Änderungen&amp;quot; wurden fünf Einträge geringerer Relevanz weggelassen, darunter die zusätzlichen Besitzprüfungen des Aktualisierungswerkzeugs, die Textüberarbeitung der Sicherheitseinstellungen, die Auswahl mehrerer Antworten über Seitengrenzen im neuen Editor sowie zwei Anpassungen an der Testpipeline.&lt;/p&gt;</description></item><item><title>Visualisierung allein reicht nicht mehr</title><link>https://markob.de/limesurvey/visualisierung-allein-reicht-nicht-mehr/</link><pubDate>Thu, 11 Jun 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/visualisierung-allein-reicht-nicht-mehr/</guid><description>&lt;p&gt;Die meisten Umfragereports beantworten die Frage: „Was zeigen die Daten?&amp;quot; Die eigentlich wichtigere Frage lautet: „Was bedeuten die Daten?&amp;quot;&lt;/p&gt;
&lt;p&gt;Das ist kein semantischer Unterschied. Es ist der Unterschied zwischen einem Bericht, den jemand liest, und einem Bericht, den jemand versteht.&lt;/p&gt;
&lt;p&gt;Visualisierung bleibt wichtig. Sie ist jedoch nicht mehr ausreichend.&lt;/p&gt;
&lt;h2 id="das-visualisierungsproblem"&gt;Das Visualisierungsproblem&lt;/h2&gt;
&lt;p&gt;Vor fünfzehn Jahren war das beeindruckend:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Frage 1 ██████████ 42 %
Frage 2 ███████ 31 %
Frage 3 █████████ 58 %
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Heute kann das jede Software. LimeSurvey. Excel. SPSS. PowerBI. Tableau. ChatGPT. Ein Balkendiagramm pro Frage ist kein Mehrwert mehr – es ist der Mindeststandard.&lt;/p&gt;</description></item><item><title>Der ehrlichste Satz in der Softwareentwicklung</title><link>https://markob.de/software-engineering/schaetzen-im-legacy-code/</link><pubDate>Fri, 05 Jun 2026 00:00:00 +0000</pubDate><guid>https://markob.de/software-engineering/schaetzen-im-legacy-code/</guid><description>&lt;p&gt;Bei Legacy-Code schätzt du nicht wie lange etwas dauert. Du schätzt, wie lange es dauert, bis du weißt, wie lange es dauert.&lt;/p&gt;
&lt;p&gt;Das klingt nach einer Ausrede. Es ist keine.&lt;/p&gt;
&lt;h2 id="warum-schätzungen-immer-falsch-sind"&gt;Warum Schätzungen immer falsch sind&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.heise.de/en/background/Won-t-fix-Part-1-Why-software-estimates-are-reliably-wrong-11304497.html"&gt;Golo Roden hat es in seiner „Won&amp;rsquo;t fix!&amp;quot;-Serie auf heise online&lt;/a&gt; gut formuliert: Softwareentwicklung ist kein Produktionsprozess. Eine Fabrik die bereits weiß wie man ein Auto baut, kann den Aufwand präzise planen. Wer Software entwickelt, erzeugt erst das Wissen das für die Lösung nötig ist. Das lässt sich nicht im Voraus messen.&lt;/p&gt;</description></item><item><title>Vom Fragebogen zum fertigen Report</title><link>https://markob.de/limesurvey/vom-fragebogen-zum-fertigen-report/</link><pubDate>Sun, 31 May 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/vom-fragebogen-zum-fertigen-report/</guid><description>&lt;p&gt;Im &lt;a href="https://markob.de/professionelle-reports"&gt;ersten Artikel&lt;/a&gt; habe ich gezeigt was das Report-Plugin produziert. Dieser Artikel zeigt den kompletten Weg dorthin – von der Umfrage bis zum fertigen Report, Schritt für Schritt.&lt;/p&gt;
&lt;p&gt;Als Beispiel dient eine Restaurant-Feedback-Umfrage. Ein alltagsnahes Szenario: Gäste bewerten ihren Besuch, das Restaurant will verstehen was gut läuft und wo Verbesserungsbedarf besteht.&lt;/p&gt;
&lt;h2 id="die-umfrage"&gt;Die Umfrage&lt;/h2&gt;
&lt;p&gt;Die Umfrage besteht aus neun Fragen – kompakt, aber ausreichend für einen differenzierten Report.&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Code&lt;/th&gt;
 &lt;th&gt;Typ&lt;/th&gt;
 &lt;th&gt;Frage&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;q1&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;L – Radio List&lt;/td&gt;
 &lt;td&gt;Wie bewerten Sie Ihren Restaurantbesuch insgesamt? (1–6)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;nps&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;L – Radio List&lt;/td&gt;
 &lt;td&gt;Wie wahrscheinlich würden Sie uns weiterempfehlen? (0–10)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;matrix&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;F – Array&lt;/td&gt;
 &lt;td&gt;Wie bewerten Sie die folgenden Aspekte? (9 Subfragen, Skala 1–6)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;anlass&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;L – Radio List&lt;/td&gt;
 &lt;td&gt;Aus welchem Anlass waren Sie bei uns?&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;besuchszeit&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;L – Radio List&lt;/td&gt;
 &lt;td&gt;Wann haben Sie uns besucht?&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;frequency&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;L – Radio List&lt;/td&gt;
 &lt;td&gt;Wie häufig besuchen Sie unser Restaurant?&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;strengths&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;M – Multiple Choice&lt;/td&gt;
 &lt;td&gt;Welche Punkte sind Ihnen besonders positiv aufgefallen?&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;potentials&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;O – List with Comment&lt;/td&gt;
 &lt;td&gt;Wo sehen Sie Verbesserungsbedarf?&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;freetext&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;T – Long Text&lt;/td&gt;
 &lt;td&gt;Möchten Sie uns noch etwas mitteilen?&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Wichtig dabei: die &lt;strong&gt;Fragen-Codes&lt;/strong&gt; – &lt;code&gt;q1&lt;/code&gt;, &lt;code&gt;nps&lt;/code&gt;, &lt;code&gt;matrix&lt;/code&gt; und so weiter. Diese Codes vergebe ich beim Anlegen der Fragen in LimeSurvey bewusst und sprechend. Sie sind der Ankerpunkt für das Mapping im nächsten Schritt.&lt;/p&gt;</description></item><item><title>Professionelle Reports für LimeSurvey</title><link>https://markob.de/limesurvey/professionelle-reports/</link><pubDate>Sat, 30 May 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/professionelle-reports/</guid><description>&lt;p&gt;LimeSurvey sammelt Daten. Was danach kommt, ist meistens bekannt: CSV-Export, Excel, PowerPoint, Eigenentwicklung. Jedes Mal manuell, jedes Mal außerhalb von LimeSurvey, jedes Mal von vorne.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Das Plugin erzeugt keine generischen Statistiken. Es erzeugt Reports.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Das ist die Lücke zwischen zu wenig und zu viel. Auf der einen Seite die eingebaute Statistikansicht – immer verfügbar, kein Aufwand, aber generisch und nicht anpassbar. Auf der anderen Seite die vollständig externe Lösung – maximale Flexibilität, aber ohne direkten Bezug zur Umfrage. Dazwischen war bisher nichts.&lt;/p&gt;</description></item><item><title>„Mach mal schnell"</title><link>https://markob.de/software-engineering/mach-mal-schnell/</link><pubDate>Mon, 25 May 2026 00:00:00 +0000</pubDate><guid>https://markob.de/software-engineering/mach-mal-schnell/</guid><description>&lt;p&gt;„Kannst du da mal schnell etwas ändern?&amp;quot; „Das ist doch nur eine Kleinigkeit.&amp;quot; „Da muss man doch nur kurz …&amp;quot;&lt;/p&gt;
&lt;p&gt;Wer länger in der Softwareentwicklung arbeitet, kennt diese Sätze. Gemeint sind sie selten böse. Trotzdem stecken darin zwei Probleme gleichzeitig: die Komplexität von Softwareänderungen wird nicht verstanden – und durch die Formulierung implizit entwertet.&lt;/p&gt;
&lt;h2 id="was-wirklich-passiert"&gt;Was wirklich passiert&lt;/h2&gt;
&lt;p&gt;Bevor eine einzige Zeile geändert wird, beginnt die eigentliche Arbeit. Frühere Entscheidungen verstehen. Abhängigkeiten erkennen. Risiken bewerten. Seiteneffekte vermeiden. Neue Entscheidungen treffen.&lt;/p&gt;</description></item><item><title>LimeSurvey Fragetypen – Einordnung aus der Praxis</title><link>https://markob.de/limesurvey/fragetypen-einordnung/</link><pubDate>Thu, 21 May 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/fragetypen-einordnung/</guid><description>&lt;p&gt;Die &lt;a href="https://markob.de/limesurvey/fragetypen"&gt;vollständige Referenz&lt;/a&gt; listet alle 28 Fragetypen auf. Dieser Artikel bewertet sie – aus der Perspektive von jemandem der seit Jahren LimeSurvey-Umfragen entwickelt, pflegt und erweitert.&lt;/p&gt;
&lt;p&gt;Die Frage ist nicht: Was kann dieser Typ? Die Frage ist: Wann ist er wirklich der richtige Ansatz?&lt;/p&gt;
&lt;h2 id="die-unverzichtbaren-typen"&gt;Die unverzichtbaren Typen&lt;/h2&gt;
&lt;p&gt;Das sind die Typen die in der Praxis fast immer ausreichen – und die man wirklich verstehen muss.&lt;/p&gt;
&lt;h3 id="liste-radio--l"&gt;Liste (Radio) · &lt;code&gt;L&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Der vielseitigste Einzelfragentyp. Vollständig konfigurierbare Antwortoptionen, optionale „Sonstige&amp;quot;-Option, gut für jede Einfachauswahl geeignet.&lt;/p&gt;</description></item><item><title>LimeSurvey Fragetypen – die vollständige Referenz</title><link>https://markob.de/limesurvey/fragetypen/</link><pubDate>Wed, 20 May 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/fragetypen/</guid><description>&lt;p&gt;LimeSurvey kennt 28 Fragetypen. Jeder Typ wird intern durch ein einzelnes Zeichen identifiziert – ein Erbe aus der frühen Entwicklungsgeschichte des Systems, das bis heute in der Datenbank, im Code und in der RemoteControl-API sichtbar ist.&lt;/p&gt;
&lt;p&gt;Diese Referenz listet alle Typen mit ihrem internen Kürzel, ihrer Struktur und einem typischen Anwendungsfall. Eine Einordnung – welche Typen in der Praxis tragen und welche nicht – folgt in einem separaten Artikel.&lt;/p&gt;
&lt;h2 id="aufbau-der-tabelle"&gt;Aufbau der Tabelle&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Kürzel&lt;/strong&gt; – das interne Zeichen wie es in der Datenbank (&lt;code&gt;questions.type&lt;/code&gt;) und im Code (&lt;code&gt;Question::QT_*&lt;/code&gt;) steht.&lt;/p&gt;</description></item><item><title>Asymmetrische Modernisierung</title><link>https://markob.de/limesurvey/asymmetrische-modernisierung/</link><pubDate>Tue, 12 May 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/asymmetrische-modernisierung/</guid><description>&lt;p&gt;Wer sich mit der &lt;code&gt;composer.json&lt;/code&gt; im &lt;code&gt;develop-major&lt;/code&gt;-Branch von LimeSurvey beschäftigt, findet dort folgendes Detail:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;config&amp;#34;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;vendor-dir&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;vendor&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;bin-dir&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;vendor/bin&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;platform&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;php&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;8.1.29&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Gleichzeitig fehlt eine explizite PHP-Anforderung:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;require&amp;#34;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;php&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;gt;=8.1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Auf den ersten Blick ein kleines technisches Detail. Tatsächlich illustriert diese Konstellation ein Muster, das man in jedem langlebigen PHP-System findet – und das erklärungsbedürftiger ist als es aussieht.&lt;/p&gt;
&lt;h2 id="was-configplatformphp-sagt"&gt;Was &lt;code&gt;config.platform.php&lt;/code&gt; sagt&lt;/h2&gt;
&lt;p&gt;Die &lt;code&gt;platform&lt;/code&gt;-Konfiguration sorgt dafür, dass Composer die Dependency-Auflösung gegen eine festgelegte PHP-Version durchführt – unabhängig davon was tatsächlich auf dem System läuft. Reproduzierbare Builds, konsistente Paketversionen, keine Überraschungen zwischen Entwicklungs- und Produktionsumgebung. Das ist vernünftig.&lt;/p&gt;</description></item><item><title>20 Jahre LimeSurvey – eine Entwicklungsgeschichte in drei Phasen</title><link>https://markob.de/limesurvey/20-jahre-limesurvey/</link><pubDate>Sun, 10 May 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/20-jahre-limesurvey/</guid><description>&lt;p&gt;Die Release Notes von LimeSurvey sind öffentlich zugänglich. Sie beginnen mit &lt;code&gt;Changes from 0.98 to 0.99&lt;/code&gt; und enden – Stand heute – bei 7.0.0-RC1 vom 30. April 2026. Über 11.000 Zeilen, die niemand vollständig liest – und die zusammen eine Geschichte erzählen, die so komprimiert nirgendwo steht.&lt;/p&gt;
&lt;p&gt;Diese Geschichte hat drei Phasen. Sie erklärt, warum LimeSurvey so ist wie es ist – und was LimeSurvey 7 jetzt konkret bedeutet.&lt;/p&gt;
&lt;h2 id="phase-1-der-aufbau-099-bis-190-20062012"&gt;Phase 1: Der Aufbau (0.99 bis ~1.90, 2006–2012)&lt;/h2&gt;
&lt;p&gt;Die frühe Phase ist bemerkenswert dicht. Innerhalb weniger Jahre entstand das konzeptuelle Fundament, auf dem LimeSurvey bis heute steht.&lt;/p&gt;</description></item><item><title>Die LimeSurvey RemoteControl API – eine kritische Betrachtung</title><link>https://markob.de/limesurvey/remotecontrol/</link><pubDate>Sun, 10 May 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/remotecontrol/</guid><description>&lt;p&gt;LimeSurvey bietet seit Version 2.0 eine Fernsteuerungsschnittstelle: die RemoteControl 2 API, kurz LSRC2. Über JSON-RPC oder XML-RPC lassen sich Umfragen anlegen, aktivieren, Teilnehmer einladen, Antworten exportieren – praktisch alles, was auch über das Webinterface möglich ist. Die Schnittstelle ist funktional, breit eingesetzt und für viele Integrationen die einzige Option.&lt;/p&gt;
&lt;p&gt;Und sie trägt dieselben Merkmale wie der Rest des Systems.&lt;/p&gt;
&lt;h2 id="was-die-api-kann"&gt;Was die API kann&lt;/h2&gt;
&lt;p&gt;Der Funktionsumfang ist beeindruckend. Umfragen anlegen, importieren, kopieren, aktivieren und löschen. Gruppen und Fragen verwalten. Teilnehmer hinzufügen, einladen, erinnern. Antworten lesen, schreiben, exportieren. Benutzer und Berechtigungen abfragen. Quoten verwalten. Feldkarten abrufen.&lt;/p&gt;</description></item><item><title>Ein typisierter LimeSurvey API-Client</title><link>https://markob.de/limesurvey/remotecontrol-api/</link><pubDate>Sun, 10 May 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/remotecontrol-api/</guid><description>&lt;p&gt;Im &lt;a href="https://markob.de/limesurvey-remotecontrol"&gt;vorherigen Artikel&lt;/a&gt; haben wir drei grundlegende Probleme der LSRC2-API identifiziert: ein zustandsbehaftetes Session-Modell, das der Aufrufer selbst verwalten muss, ein inkonsistentes Rückgabeformat das Erfolg und Fehler nicht unterscheidet, und einen empfohlenen Client, der LimeSurvey-Konzepte nicht kennt.&lt;/p&gt;
&lt;p&gt;Dieser Artikel zeigt, wie ein typisierter Client diese Probleme löst – nicht als vollständige Implementierung, sondern als Lösungsvorschlag anhand konkreter Beispiele.&lt;/p&gt;
&lt;h2 id="die-ausgangslage"&gt;Die Ausgangslage&lt;/h2&gt;
&lt;p&gt;Ein typischer Aufruf mit dem rohen &lt;code&gt;JsonRPCClient&lt;/code&gt; sieht so aus:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;JsonRPCClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;https://example.com/index.php/admin/remotecontrol&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$sessionKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;get_session_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;admin&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;password&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;add_survey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$sessionKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Meine Umfrage&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;de&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;is_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;status&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// Fehler
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;status&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// Erfolg – $result ist ein int
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$surveyId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;release_session_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$sessionKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Drei Probleme in acht Zeilen: Der Session-Key muss manuell übergeben und am Ende freigegeben werden. Der Rückgabetyp ist unbekannt bis man ihn prüft. Und was genau in &lt;code&gt;$result['status']&lt;/code&gt; steht, weiß man erst zur Laufzeit.&lt;/p&gt;</description></item><item><title>Das LimeSurvey Plugin-Event-System – eine kritische Betrachtung</title><link>https://markob.de/limesurvey/plugin-event-kritik/</link><pubDate>Sat, 09 May 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/plugin-event-kritik/</guid><description>&lt;p&gt;LimeSurvey verfügt über ein event-basiertes Plugin-System. Plugins abonnieren Events, reagieren darauf, und können Daten zurückgeben. Das Konzept ist solide – und weit verbreitet in modernen Frameworks. Die Implementierung erzählt eine andere Geschichte.&lt;/p&gt;
&lt;h2 id="was-ein-event-system-leisten-soll"&gt;Was ein Event-System leisten soll&lt;/h2&gt;
&lt;p&gt;Ein Event kommuniziert, dass etwas passiert ist oder passieren wird. Der Name beschreibt das Ereignis. Die Parameter sind bekannt und garantiert. Der Empfänger reagiert – er fragt nicht erst nach, ob die Daten überhaupt vorhanden sind.&lt;/p&gt;</description></item><item><title>newDirectRequest – vollständige Webanwendungen im LimeSurvey-Plugin</title><link>https://markob.de/limesurvey/newdirectrequest-event/</link><pubDate>Sat, 09 May 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/newdirectrequest-event/</guid><description>&lt;p&gt;Der &lt;a href="https://markob.de/limesurvey-direct-event"&gt;&lt;code&gt;direct&lt;/code&gt;-Event&lt;/a&gt; ist der CLI-Einstiegspunkt für LimeSurvey-Plugins. &lt;code&gt;newDirectRequest&lt;/code&gt; ist sein HTTP-Pendant: ein Plugin wird über den Browser angesprochen, bekommt einen vollständigen HTTP-Request, und kann eine vollständige HTTP-Response zurückgeben.&lt;/p&gt;
&lt;p&gt;Was LimeSurvey dabei nicht mitliefert, ist Routing. Der Event landet im Plugin – was danach passiert, ist vollständig in der Verantwortung des Plugin-Entwicklers.&lt;/p&gt;
&lt;h2 id="wie-newdirectrequest-funktioniert"&gt;Wie &lt;code&gt;newDirectRequest&lt;/code&gt; funktioniert&lt;/h2&gt;
&lt;p&gt;Die URL, unter der ein Plugin erreichbar ist, folgt diesem Schema:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;https://example.com/index.php/plugins/direct/plugin/MeinPlugin
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Das Plugin abonniert den Event in &lt;code&gt;init()&lt;/code&gt; und prüft das Target – analog zu &lt;code&gt;direct&lt;/code&gt;, aber case-insensitiv, da URL-Parameter in der Praxis nicht immer exakt geschrieben werden:&lt;/p&gt;</description></item><item><title>Yii commands in LimeSurvey-Plugins</title><link>https://markob.de/limesurvey/yii-commands/</link><pubDate>Sat, 09 May 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/yii-commands/</guid><description>&lt;p&gt;Der &lt;a href="https://markob.de/limesurvey/direct-event"&gt;&lt;code&gt;direct&lt;/code&gt;-Event&lt;/a&gt; ist der offizielle CLI-Einstiegspunkt für LimeSurvey-Plugins – schlank, gezielt, gut für einfache Cronjobs. Aber er hat eine feste Grenze: drei Parameter, kein Routing, keine Argument-Validierung. Wer komplexere Kommandos braucht, stößt schnell an diese Grenze.&lt;/p&gt;
&lt;p&gt;Yii 1.1 bringt ein eigenes Command-System mit, das deutlich mächtiger ist. Und es lässt sich so in ein Plugin integrieren, dass die Plugin-Kapselung vollständig erhalten bleibt.&lt;/p&gt;
&lt;h2 id="was-yii-commands-können"&gt;Was Yii Commands können&lt;/h2&gt;
&lt;p&gt;Ein Yii Command ist eine Klasse, die von &lt;code&gt;CConsoleCommand&lt;/code&gt; erbt. In der einfachsten Form überschreibt sie &lt;code&gt;run()&lt;/code&gt;:&lt;/p&gt;</description></item><item><title>Der direct-Event, gezielter CLI-Einstieg für LimeSurvey-Plugins</title><link>https://markob.de/limesurvey/direct-event/</link><pubDate>Fri, 08 May 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/direct-event/</guid><description>&lt;p&gt;Wenn ein Plugin nicht auf eine Benutzeraktion im Browser reagieren soll, sondern auf der Kommandozeile aufgerufen werden – für einen Cronjob, einen Datenexport, eine nächtliche Bereinigung –, dann ist &lt;code&gt;direct&lt;/code&gt; der richtige Einstiegspunkt.&lt;/p&gt;
&lt;h2 id="das-minimalbeispiel"&gt;Das Minimalbeispiel&lt;/h2&gt;
&lt;p&gt;Ein LimeSurvey-Plugin besteht aus mindestens zwei Dateien:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;upload/plugins/HelloWorld/
 config.xml
 HelloWorld.php
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Der Verzeichnisname, der Klassenname und der &lt;code&gt;&amp;lt;name&amp;gt;&lt;/code&gt;-Eintrag in der &lt;code&gt;config.xml&lt;/code&gt; müssen identisch sein.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;config&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;metadata&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;HelloWorld&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;type&amp;gt;&lt;/span&gt;plugin&lt;span class="nt"&gt;&amp;lt;/type&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.0.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;author&amp;gt;&lt;/span&gt;My Name&lt;span class="nt"&gt;&amp;lt;/author&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;description&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;![CDATA[Hello World via CLI]]&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/metadata&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;compatibility&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;6.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;5.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/compatibility&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/config&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HelloWorld&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;PluginBase&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$storage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;LimeSurvey\PluginManager\DbStorage&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;HelloWorld&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;HelloWorld&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;direct&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;direct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getEvent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;target&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;get_class&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;HELLO WORLD&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;PHP_EOL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nach der Aktivierung im Plugin-Manager wird das Plugin so aufgerufen:&lt;/p&gt;</description></item><item><title>LimeSurvey und Composer – eine ungewöhnliche Beziehung</title><link>https://markob.de/limesurvey/composer/</link><pubDate>Fri, 08 May 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/composer/</guid><description>&lt;p&gt;Wer aus moderner PHP-Entwicklung kommt, hat bestimmte Erwartungen. Ein Projekt hat eine &lt;code&gt;composer.json&lt;/code&gt;. Der &lt;code&gt;vendor/&lt;/code&gt;-Ordner ist in &lt;code&gt;.gitignore&lt;/code&gt;. Nach einem &lt;code&gt;git clone&lt;/code&gt; folgt &lt;code&gt;composer install&lt;/code&gt; – erst dann läuft etwas. Das ist der Standard, den Composer seit über zehn Jahren etabliert hat.&lt;/p&gt;
&lt;p&gt;Bei LimeSurvey funktioniert das anders.&lt;/p&gt;
&lt;h2 id="der-erste-hinweis"&gt;Der erste Hinweis&lt;/h2&gt;
&lt;p&gt;Eine lokale LimeSurvey-Installation beginnt typischerweise so:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git clone https://github.com/LimeSurvey/LimeSurvey.git
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Danach folgt der webbasierte Installer im Browser – Datenbankverbindung einrichten, Tabellen anlegen, Admin-Account erstellen. Fertig. Ein &lt;code&gt;composer install&lt;/code&gt; ist zu keinem Zeitpunkt nötig.&lt;/p&gt;</description></item><item><title>SurveyIndex + SurveyRuntimeHelper – Anatomie eines God Flow</title><link>https://markob.de/limesurvey/god-flow/</link><pubDate>Wed, 06 May 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/god-flow/</guid><description>&lt;p&gt;Wenn zu viel Verantwortung nicht in einer Klasse steckt, sondern in einem Ablauf&lt;/p&gt;
&lt;p&gt;In den letzten Artikeln dieser Serie haben wir zwei bekannte Antipattern betrachtet: &lt;a href="https://markob.de/create-field-map-die-god-function"&gt;&lt;code&gt;createFieldMap()&lt;/code&gt;&lt;/a&gt; als Beispiel einer Funktion, die zu viele Verantwortlichkeiten in sich vereint, und &lt;a href="https://markob.de/limemailer-anatomie-einer-god-class"&gt;&lt;code&gt;LimeMailer&lt;/code&gt;&lt;/a&gt; als Beispiel einer Klasse, die zu viel weiß, zu viel hält und zu viel tut. Beide Diagnosen folgten derselben Logik: Zu viel Verantwortung an einer Stelle.&lt;/p&gt;
&lt;p&gt;Diesmal geht es um etwas anderes. Nicht eine Funktion. Nicht eine Klasse. Sondern einen Ablauf.&lt;/p&gt;</description></item><item><title>LimeSurvey neu gedacht</title><link>https://markob.de/limesurvey/neu-gedacht/</link><pubDate>Tue, 05 May 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/neu-gedacht/</guid><description>&lt;p&gt;Dieser Artikel ist ein Gedankenexperiment. Er setzt voraus, was in der Realität selten gegeben ist: ausreichend Zeit, ausreichend Ressourcen und das Mandat, wirklich neu zu denken – nicht nur neu zu schreiben.&lt;/p&gt;
&lt;p&gt;Wir haben in dieser Serie viel über Geduld gesprochen. Über schrittweise Migration, über Composer Packages, über den Wert des akkumulierten Wissens. Über &lt;code&gt;createFieldMap()&lt;/code&gt; und ihre 13 Jahre alten Kommentare. Über den Expression Manager, der 15 Jahre unberührt blieb, weil ihn niemand anfassen konnte.&lt;/p&gt;</description></item><item><title>Wenn „never" die richtige Antwort ist</title><link>https://markob.de/limesurvey/wenn-never-die-richtige-antwort-ist/</link><pubDate>Sun, 03 May 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/wenn-never-die-richtige-antwort-ist/</guid><description>&lt;p&gt;Im Artikel &lt;a href="https://markob.de/rewrite-reflex"&gt;Der Rewrite-Reflex&lt;/a&gt; haben wir argumentiert, warum der Impuls neu zu schreiben meistens falsch ist. Akkumuliertes Wissen geht verloren. Die neuen Entwickler treffen dieselben alten Entscheidungen – diesmal ohne den Kontext der sie damals erklärt hätte. Ein Rewrite beginnt bei null. Sauber. Modern. Ohne dieses Wissen.&lt;/p&gt;
&lt;p&gt;Im Artikel &lt;a href="https://markob.de/refactoring-kosten"&gt;Refactoring – was kostet es, was kostet es nicht?&lt;/a&gt; haben wir gesagt: &lt;em&gt;„Later braucht einen Termin.&amp;quot;&lt;/em&gt; Technische Schulden akkumulieren stille Kosten. Wer nie neu bewertet, trifft keine Entscheidung – er lässt die Entscheidung treffen.&lt;/p&gt;</description></item><item><title>Refactoring – was kostet es, was kostet es nicht?</title><link>https://markob.de/limesurvey/refactoring-kosten/</link><pubDate>Thu, 30 Apr 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/refactoring-kosten/</guid><description>&lt;p&gt;Im &lt;a href="https://markob.de/create-field-map-die-god-function"&gt;Artikel über &lt;code&gt;createFieldMap()&lt;/code&gt;&lt;/a&gt; haben wir gesehen was eine GodFunction ist, wie sie entsteht, und wie ein Weg heraus aussehen könnte: ein sauberes Composer Package, vollständige QA-Kette, 100% Testbarkeit.&lt;/p&gt;
&lt;p&gt;Der Plan ist klar. Die Frage die danach kommt, ist schwieriger:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Was kostet das? Und was kostet es, es nicht zu tun?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Das ist keine technische Frage mehr. Das ist eine unternehmerische. Und sie landet früher oder später auf dem Tisch des CTOs oder Lead Developers – meistens dann wenn das Budget knapp ist und die Roadmap voll.&lt;/p&gt;</description></item><item><title>createFieldMap() – die God Function</title><link>https://markob.de/limesurvey/create-field-map-die-god-function/</link><pubDate>Sun, 26 Apr 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/create-field-map-die-god-function/</guid><description>&lt;p&gt;&lt;a href="https://markob.de/limesurvey/helper-funktionen"&gt;Im Artikel über die Helper-Funktionen&lt;/a&gt; haben wir &lt;code&gt;common_helper.php&lt;/code&gt; als Ganzes betrachtet – 130+ globale Funktionen, über 11.000 Aufrufe im Code, ein Relikt aus der prozeduralen Ära. &lt;a href="https://markob.de/limemailer-anatomie-einer-god-class"&gt;In einem anderen Artikel&lt;/a&gt; haben wir &lt;code&gt;LimeMailer&lt;/code&gt; als GodClass analysiert: eine Klasse die zu viel weiß, zu viel tut, und deshalb praktisch nicht testbar ist.&lt;/p&gt;
&lt;p&gt;Heute schauen wir auf etwas das noch subtiler ist: eine &lt;strong&gt;GodFunction&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Keine Klasse. Eine einzelne Funktion. Mit über 600 Zeilen Code.&lt;/p&gt;</description></item><item><title>Das weiße Blatt</title><link>https://markob.de/software-engineering/das-weisse-blatt/</link><pubDate>Mon, 20 Apr 2026 00:00:00 +0000</pubDate><guid>https://markob.de/software-engineering/das-weisse-blatt/</guid><description>&lt;p&gt;Wer lange mit gewachsenen Systemen gearbeitet hat, entwickelt eine bestimmte Art zu denken. Man sieht nicht nur, was ein Werkzeug kann – man sieht, was es einem aufzwingt. Welche Entscheidungen es vorwegnimmt. Welche Wege es versperrt, bevor man überhaupt angefangen hat.&lt;/p&gt;
&lt;p&gt;Das weiße Blatt ist selten. In der Praxis arbeitet man fast immer im Bestand – mit Legacy-Code, mit bestehenden Abhängigkeiten, mit Entscheidungen, die jemand anderes vor Jahren getroffen hat. Das ist der Alltag, und diese Serie handelt davon.&lt;/p&gt;</description></item><item><title>Wann hört Legacy auf, Legacy zu sein?</title><link>https://markob.de/limesurvey/wann-hoert-legacy-auf-legacy-zu-sein/</link><pubDate>Sun, 19 Apr 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/wann-hoert-legacy-auf-legacy-zu-sein/</guid><description>&lt;p&gt;Im Artikel &lt;a href="https://markob.de/der-rewrite-reflex"&gt;Der Rewrite-Reflex&lt;/a&gt; haben wir uns gefragt, warum Entwickler beim Anblick einer gewachsenen Codebasis sofort neu schreiben wollen – und warum das meistens ein Fehler ist. Die Alternative lautet: verstehen statt ersetzen. Schrittweise Entflechtung. Abhängigkeiten sichtbar machen. Vorhandenes Wissen bewahren.&lt;/p&gt;
&lt;p&gt;Das ist der Weg. Aber wohin führt er?&lt;/p&gt;
&lt;p&gt;Wann ist man fertig? Wann hört Legacy auf, Legacy zu sein?&lt;/p&gt;
&lt;p&gt;Ich habe lange gebraucht um zu merken, dass ich diese Frage nie wirklich gestellt hatte. Und als ich sie stellte, merkte ich: die meisten können sie nicht beantworten.&lt;/p&gt;</description></item><item><title>Was bleibt vom Entwickler</title><link>https://markob.de/software-engineering/was-bleibt-vom-entwickler/</link><pubDate>Wed, 15 Apr 2026 00:00:00 +0000</pubDate><guid>https://markob.de/software-engineering/was-bleibt-vom-entwickler/</guid><description>&lt;h2 id="was-ich-nicht-mehr-tue"&gt;Was ich nicht mehr tue&lt;/h2&gt;
&lt;p&gt;Ich schreibe heute kaum noch Code. Nicht weil ich es nicht kann – sondern weil die KI schneller, konsistenter und ohne die kleinen Flüchtigkeitsfehler arbeitet, die sich in langen Arbeitstagen einschleichen.&lt;/p&gt;
&lt;p&gt;Ich tippe keine Boilerplate mehr, keine Konstruktoren, Getter oder wiederholenden Strukturen.&lt;/p&gt;
&lt;p&gt;Das klingt nach Verlust. Ist es aber nicht. Das Handwerk war nie der interessante Teil. Wertvoll war immer das Verstehen des Problems und das Urteil über die Lösung – alles, was der KI nicht abgenommen werden kann.&lt;/p&gt;</description></item><item><title>LimeSurvey und Yii – eine Framework-Geschichte</title><link>https://markob.de/limesurvey/yii/</link><pubDate>Sun, 12 Apr 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/yii/</guid><description>&lt;p&gt;Es gibt Entscheidungen in der Softwareentwicklung, die man bewusst trifft.&lt;br&gt;
Und es gibt Entscheidungen, die man trifft, weil man keine andere Wahl hat.&lt;br&gt;
Die Entscheidung, mit der LimeSurvey 2012 zu Yii 1.1 gewechselt hat, war die zweite Art.&lt;/p&gt;
&lt;p&gt;Aber fangen wir von vorne an.&lt;/p&gt;
&lt;h2 id="prado--der-anfang-einer-linie"&gt;Prado – der Anfang einer Linie&lt;/h2&gt;
&lt;p&gt;Im Juni 2004 veröffentlichte der chinesische Entwickler &lt;strong&gt;Qiang Xue&lt;/strong&gt; die erste Version eines PHP-Frameworks namens &lt;strong&gt;PRADO&lt;/strong&gt; – &lt;em&gt;PHP Rapid Application Development Object-oriented&lt;/em&gt;. PHP 5.0 war gerade frisch erschienen, und Zend hatte einen Wettbewerb ausgeschrieben um die neue Version zu fördern. Qiang reimplementierte Prado für PHP 5 – und gewann.&lt;/p&gt;</description></item><item><title>Wie PHPStan Legacy-Code sichtbar macht</title><link>https://markob.de/limesurvey/wie-phpstan-legacy-code-sichtbar-macht/</link><pubDate>Sun, 05 Apr 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/wie-phpstan-legacy-code-sichtbar-macht/</guid><description>&lt;p&gt;Im &lt;a href="https://markob.de/helper-funktionen"&gt;ersten Artikel&lt;/a&gt; haben wir uns angesehen, was &lt;code&gt;Yii::app()-&amp;gt;loadHelper()&lt;/code&gt; eigentlich macht, warum die &lt;code&gt;common_helper.php&lt;/code&gt; architektonisch ein Problem ist und wie der Weg heraus aussehen könnte: Composer Autoloading, Service-Klassen, saubere Abhängigkeiten.&lt;/p&gt;
&lt;p&gt;Was wir damals nicht hatten: &lt;strong&gt;Zahlen.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Wie oft wird eine Funktion aus &lt;code&gt;common_helper.php&lt;/code&gt; eigentlich aufgerufen? Welche Funktionen sind so gut wie tot und können sofort gelöscht werden? Und welche sind so tief im Code verwurzelt, dass eine Migration echte Arbeit bedeutet?&lt;/p&gt;</description></item><item><title>Die Schnecke</title><link>https://markob.de/software-engineering/die-schnecke/</link><pubDate>Wed, 01 Apr 2026 00:00:00 +0000</pubDate><guid>https://markob.de/software-engineering/die-schnecke/</guid><description>&lt;p&gt;Ich habe heute zufällig eine Grafik gesehen, die oft gezeigt wird, wenn jemand Scrum erklärt.&lt;br&gt;
Ein großer Kreis mit einem kleineren Kreis darin, der sich hineinschraubt. Der Sprint dreht sich, der Daily Stand-Up dreht sich darin.&lt;br&gt;
Darunter ein Fließband: Backlog, Planning, Sprint-Backlog, Sprint, Finished Work. Von links nach rechts.&lt;/p&gt;
&lt;p&gt;Eine Schnecke.&lt;/p&gt;
&lt;p&gt;Die Schnecke ist kein schlechtes Tier. Sie ist beständig, anpassungsfähig, kommt ans Ziel. Aber agil?&lt;br&gt;
Nicht das erste Wort, das einem einfällt. Und doch trägt die bekannteste Visualisierung eines der einflussreichsten&lt;br&gt;
agilen Frameworks ihr Bild.&lt;/p&gt;</description></item><item><title>LimeSurvey und die Helper-Funktionen</title><link>https://markob.de/limesurvey/helper-funktionen/</link><pubDate>Sun, 29 Mar 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/helper-funktionen/</guid><description>&lt;p&gt;Wer LimeSurvey als Plugin-Entwickler nutzt oder in der Codebasis arbeitet, begegnet früher oder später diesem Muster:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;Yii&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;loadHelper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;common&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;Yii&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;loadHelper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;surveytranslator&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;Yii&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;loadHelper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;replacements&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Dahinter steckt ein einfacher Mechanismus: &lt;code&gt;loadHelper('common')&lt;/code&gt; lädt die Datei &lt;code&gt;application/helpers/common_helper.php&lt;/code&gt; und macht ihre Funktionen im globalen Scope verfügbar. Dasselbe Muster findet sich auch bei &lt;code&gt;loadLibrary()&lt;/code&gt;, das auf &lt;code&gt;application/libraries/&lt;/code&gt; zeigt:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loadHelper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$helper&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Yii&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;application.helpers.&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$helper&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;_helper&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loadLibrary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$library&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Yii&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;application.libraries.&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$library&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Der konzeptuelle Unterschied zwischen Helper und Library ist dabei in der LimeSurvey-Codebasis kaum greifbar – beide Mechanismen lösen dasselbe Problem auf dieselbe Art. Das war in einer Zeit sinnvoll, als PHP noch kein Autoloading kannte und Funktionen manuell eingebunden werden mussten. PHP 5.1 war 2005. Composer erschien 2012.&lt;/p&gt;</description></item><item><title>LimeMailer - Anatomie einer God Class</title><link>https://markob.de/limesurvey/limemailer-anatomie-einer-god-class/</link><pubDate>Sun, 22 Mar 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/limemailer-anatomie-einer-god-class/</guid><description>&lt;p&gt;&lt;a href="https://github.com/LimeSurvey/LimeSurvey/blob/master/application/core/LimeMailer.php"&gt;LimeMailer&lt;/a&gt; ist die zentrale E-Mail-Komponente von LimeSurvey. Sie erbt von PHPMailer, der weit verbreiteten PHP-Mailer-Bibliothek, und erweitert diese um LimeSurvey-spezifische Logik: Umfrage-Templates, Token-Ersetzungen, Anhänge nach E-Mail-Typ, Plugin-Events und vieles mehr.&lt;/p&gt;
&lt;p&gt;Dieser Artikel betrachtet die Klasse nicht als Fehler ihrer Entwickler. Wer in einem laufenden Open-Source-Projekt unter Zeitdruck Features liefert, trifft Entscheidungen, die im Moment vernünftig sind. Technische Schulden entstehen nicht durch Unwissenheit, sondern durch die Realität von Softwareentwicklung. Was hier analysiert wird, ist das Muster – nicht die Person dahinter.&lt;/p&gt;</description></item><item><title>LimeSurvey und wie Antworten gespeichert werden</title><link>https://markob.de/limesurvey/datenmodell/</link><pubDate>Fri, 20 Mar 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/datenmodell/</guid><description>&lt;p&gt;Die Art, wie LimeSurvey Umfrageantworten speichert, gehört zu den ältesten und fundamentalsten Architekturentscheidungen der Plattform. Sie beeinflusst alles, was darüber liegt: Plugins, Integrationen, Reporting und die Erweiterbarkeit des Systems.&lt;/p&gt;
&lt;p&gt;Wer mit LimeSurvey arbeitet, kommt früher oder später mit dieser Struktur in Berührung – spätestens dann, wenn Antwortdaten außerhalb der Plattform ausgewertet oder in eigene Systeme integriert werden sollen.&lt;/p&gt;
&lt;h2 id="survey-spezifische-antworttabellen"&gt;Survey-spezifische Antworttabellen&lt;/h2&gt;
&lt;p&gt;Für jede Umfrage legt LimeSurvey eine eigene Datenbanktabelle an. Der Tabellenname folgt dem Schema&lt;/p&gt;</description></item><item><title>LimeSurvey und die Hungarian Notation</title><link>https://markob.de/limesurvey/hungarian-notation/</link><pubDate>Sun, 15 Mar 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/hungarian-notation/</guid><description>&lt;p&gt;Wer schon einmal einen Blick in den Quellcode von LimeSurvey geworfen hat, dem begegnet unweigerlich Folgendes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$iSurveyId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$sLanguage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;de&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$oSurvey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Survey&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;findByPk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$iSurveyId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$aQuestions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$oSurvey&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getQuestions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$bActive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Das Präfix verrät den Typ: &lt;code&gt;i&lt;/code&gt; für Integer, &lt;code&gt;s&lt;/code&gt; für String, &lt;code&gt;o&lt;/code&gt; für Object, &lt;code&gt;a&lt;/code&gt; für Array, &lt;code&gt;b&lt;/code&gt; für Boolean. Diese Konvention nennt sich Hungarian Notation – und sie stammt aus einer Zeit, in der PHP noch keinerlei Typisierung kannte. LimeSurvey existiert seit über 20 Jahren, und manche dieser Muster sind genauso alt.&lt;/p&gt;</description></item><item><title>Der Rewrite-Reflex</title><link>https://markob.de/limesurvey/rewrite-reflex/</link><pubDate>Sun, 08 Mar 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/rewrite-reflex/</guid><description>&lt;p&gt;Wer zum ersten Mal in eine gewachsene Codebasis eintaucht – unbekannte Strukturen, kryptische Bezeichner, Abhängigkeiten, die sich wie ein Geflecht durch das System ziehen – kennt den Impuls: &lt;strong&gt;neu schreiben.&lt;/strong&gt; Sauber. Modern. Diesmal richtig.&lt;/p&gt;
&lt;p&gt;Dieser Reflex ist verständlich. Er ist menschlich. Und er ist einer der teuersten Fehler, den ein Entwicklungsteam machen kann.&lt;/p&gt;
&lt;h2 id="was-ist-legacy-code-überhaupt"&gt;Was ist Legacy-Code überhaupt?&lt;/h2&gt;
&lt;p&gt;Bevor man über Rewrite oder Modernisierung spricht, lohnt sich ein Blick auf die Frage: &lt;strong&gt;Was ist Legacy-Code?&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>LimeSurvey - ein System im Übergang</title><link>https://markob.de/limesurvey/ein-system-im-uebergang/</link><pubDate>Sun, 01 Mar 2026 00:00:00 +0000</pubDate><guid>https://markob.de/limesurvey/ein-system-im-uebergang/</guid><description>&lt;h2 id="was-ist-limesurvey"&gt;Was ist LimeSurvey?&lt;/h2&gt;
&lt;p&gt;LimeSurvey gehört seit vielen Jahren zu den meistverbreiteten Open-Source-Umfragelösungen im PHP-Ökosystem. Die Plattform ermöglicht die Erstellung, Verwaltung und Auswertung von Online-Umfragen und richtet sich sowohl an einzelne Anwender als auch an Organisationen mit komplexen Anforderungen. Mit einer großen aktiven Installationsbasis und kontinuierlicher Weiterentwicklung ist LimeSurvey ein Projekt, das seit langem produktiv eingesetzt wird. Für Umfragen im akademischen oder organisatorischen Kontext gibt es kaum eine vergleichbare Open-Source-Alternative mit diesem Funktionsumfang.&lt;/p&gt;</description></item><item><title>Archiv</title><link>https://markob.de/archiv/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://markob.de/archiv/</guid><description/></item><item><title>Herausforderungen</title><link>https://markob.de/herausforderungen/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://markob.de/herausforderungen/</guid><description>&lt;p&gt;Viele Probleme rund um Befragungen zeigen sich nicht als eine Frage, sondern als ein Gefühl: die Auswertung dauert zu lange, das Plugin ist gewachsen, aber niemand traut sich mehr, es anzufassen, oder die Ergebnisse liegen vor, aber die eigentliche Entscheidung ist trotzdem nicht klarer geworden.&lt;/p&gt;
&lt;p&gt;Im Folgenden typische Herausforderungen, denen ich in Projekten immer wieder begegne. Vielleicht erkennen Sie eine davon wieder.&lt;/p&gt;
&lt;h2 id="die-befragung-liefert-antworten-aber-keine-entscheidungsgrundlage"&gt;Die Befragung liefert Antworten, aber keine Entscheidungsgrundlage&lt;/h2&gt;
&lt;p&gt;Der Fragebogen ist fertig, die Daten kommen rein – aber am Ende steht trotzdem die Frage: Und was folgt jetzt daraus? Häufig wurde die Umfrage aus der Frage heraus entworfen, nicht aus der Entscheidung, die sie eigentlich stützen sollte.&lt;/p&gt;</description></item><item><title>Impressum</title><link>https://markob.de/impressum/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://markob.de/impressum/</guid><description>&lt;h2 id="anbieter"&gt;Anbieter&lt;/h2&gt;
&lt;p&gt;Marko Bischof&lt;br&gt;
Nordfeldstr 21&lt;br&gt;
30459 Hannover&lt;/p&gt;
&lt;h2 id="kontakt"&gt;Kontakt&lt;/h2&gt;
&lt;p&gt;E-Mail: &lt;a href="mailto:marko.bischof@gmail.com"&gt;marko.bischof@gmail.com&lt;/a&gt;&lt;br&gt;
Website: &lt;a href="https://markob.de"&gt;https://markob.de&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="verantwortlich-für-den-inhalt-nach--18-abs-2-mstv"&gt;Verantwortlich für den Inhalt nach § 18 Abs. 2 MStV&lt;/h2&gt;
&lt;p&gt;Marko Bischof&lt;br&gt;
Nordfeldstr 21&lt;br&gt;
30459 Hannover&lt;/p&gt;
&lt;h2 id="haftung-für-inhalte"&gt;Haftung für Inhalte&lt;/h2&gt;
&lt;p&gt;Die Inhalte unserer Seiten wurden mit größter Sorgfalt erstellt. Für die&lt;br&gt;
Richtigkeit, Vollständigkeit und Aktualität der Inhalte können wir jedoch keine&lt;br&gt;
Gewähr übernehmen. Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG für eigene&lt;br&gt;
Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach&lt;br&gt;
§§ 8 bis 10 TMG sind wir als Diensteanbieter jedoch nicht verpflichtet,&lt;br&gt;
übermittelte oder gespeicherte fremde Informationen zu überwachen oder nach&lt;br&gt;
Umständen zu forschen, die auf eine rechtswidrige Tätigkeit hinweisen.&lt;/p&gt;</description></item><item><title>Lösungen</title><link>https://markob.de/loesungen/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://markob.de/loesungen/</guid><description>&lt;p&gt;Jedes Unternehmen, jede Behörde und jede Forschungseinrichtung hat andere Anforderungen an Online-Befragungen. Manche möchten die Zufriedenheit ihrer Mitarbeitenden messen, andere benötigen automatisierte Reports oder individuelle Erweiterungen für LimeSurvey.&lt;/p&gt;
&lt;p&gt;Im Folgenden finden Sie typische Anwendungsfälle. Vielleicht ist Ihrer bereits dabei – und falls nicht, entwickeln wir gemeinsam eine passende Lösung.&lt;/p&gt;
&lt;h2 id="automatische-ergebnisberichte"&gt;Automatische Ergebnisberichte&lt;/h2&gt;
&lt;p&gt;Aus den Antworten Ihrer Umfrage entstehen automatisch professionell gestaltete Berichte – abgestimmt auf die Entscheidung, die sie stützen sollen, nicht nur auf die Rohdaten.&lt;/p&gt;</description></item><item><title>Marko Bischof</title><link>https://markob.de/ueber-mich/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://markob.de/ueber-mich/</guid><description>&lt;p&gt;Ich entwickle seit über 20 Jahren PHP-Systeme. Nicht weil ich nichts anderes kenne, sondern weil es ein Handwerk ist, das Tiefe verlangt — und weil gewachsene Anwendungen eine eigene Intelligenz haben, die man erst mit der Zeit versteht.&lt;/p&gt;
&lt;p&gt;Seit knapp acht Jahren arbeite ich im LimeSurvey-Ökosystem: Plugin-Entwicklung, Datenbankmodell, Expression Manager, die Grenzen der Plattform und die Stellen, an denen Modernisierung realistisch ansetzt.&lt;/p&gt;
&lt;h2 id="wie-ich-arbeite"&gt;Wie ich arbeite&lt;/h2&gt;
&lt;p&gt;Ich glaube nicht an den großen Rewrite. Gewachsene Systeme tragen akkumuliertes Wissen in sich — in jeder seltsamen Konstruktion steckt eine Geschichte, ein Grenzfall oder eine Entscheidung unter echten Produktionsbedingungen. Dieses Wissen wegzuwerfen ist teuer.&lt;/p&gt;</description></item></channel></rss>