<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Thomas Panzeri</title>
    <link>https://panzeri.rocks/de/</link>
    <description>Thomas Panzeri baut Software und baut IT-Organisationen von innen um, damit Firmen, die sich verändern müssen, modern entwickeln können.</description>
    <language>de-CH</language>
    <atom:link href="https://panzeri.rocks/de/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>panzeri.rocks neu gebaut</title>
      <link>https://panzeri.rocks/de/writing/rebuilding-panzeri-rocks/</link>
      <pubDate>Sun, 11 Oct 2026 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/rebuilding-panzeri-rocks/</guid>
      <description>&lt;p&gt;Diese Seite hatte in drei Jahren drei Versionen. Die letzte ist die erste, die um das Schreiben herum gebaut ist statt um ein Werkzeug.&lt;/p&gt;&#xA;&lt;h2 id=&#34;wo-es-anfing&#34;&gt;Wo es anfing&lt;/h2&gt;&#xA;&lt;p&gt;Die erste Version, im Mai 2023, war Hugo mit einem fertigen Theme: eine Startseite, eine Über-mich-Seite und ein paar Cheat Sheets, als Git-Submodul eingebunden. Bei jedem Build wählte sie sogar eine neue Akzentfarbe. Sie funktionierte und sah aus wie jede andere Hugo-Seite.&lt;/p&gt;&#xA;&lt;p&gt;Das war in Ordnung. Niemand besucht eine persönliche Seite wegen des Themes. Man kommt wegen etwas, das du geschrieben hast, liest es und geht wieder.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Websites sind Dateien</title>
      <link>https://panzeri.rocks/de/writing/static-sites-with-hugo/</link>
      <pubDate>Thu, 24 Sep 2026 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/static-sites-with-hugo/</guid>
      <description>&lt;p&gt;Der zehnte und letzte Teil des Boring Stack. Die ersten neun handelten von Apps. Dieser handelt vom einfacheren Fall: Websites wie einem Blog, einer Kampagnenseite oder einer Infoseite für einen Verein.&lt;/p&gt;&#xA;&lt;p&gt;Sie brauchen kein Backend. Also bekommen sie keines.&lt;/p&gt;&#xA;&lt;h2 id=&#34;einmal-erzeugt-als-dateien-ausgeliefert&#34;&gt;Einmal erzeugt, als Dateien ausgeliefert&lt;/h2&gt;&#xA;&lt;p&gt;Hugo ist ein Static Site Generator. Er nimmt Markdown-Dateien, Templates und eine Konfigurationsdatei und erzeugt einen Ordner mit einfachem HTML, CSS und Bildern. Dieser Ordner ist die Website. Jeder Webserver kann ihn ausliefern, und auf &lt;a href=&#34;https://panzeri.rocks/de/writing/one-vps/&#34;&gt;meinem Server&lt;/a&gt; tut das Caddy.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Ein Server ist leicht zu durchschauen</title>
      <link>https://panzeri.rocks/de/writing/one-vps/</link>
      <pubDate>Thu, 27 Aug 2026 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/one-vps/</guid>
      <description>&lt;p&gt;Teil neun des Boring Stack. Die App ist &lt;a href=&#34;https://panzeri.rocks/de/writing/why-go/&#34;&gt;ein einzelnes Go-Binary&lt;/a&gt; mit &lt;a href=&#34;https://panzeri.rocks/de/writing/sqlite-is-enough/&#34;&gt;ihren Daten in einer SQLite-Datei&lt;/a&gt;. Wo soll das laufen?&lt;/p&gt;&#xA;&lt;p&gt;Die modischen Antworten sind eine verwaltete Plattform, Serverless-Funktionen oder ein Kubernetes-Cluster. Ich habe Kubernetes auf Bare Metal betrieben und auf dieser Seite darüber geschrieben. Für meine eigenen Apps miete ich einen virtuellen Server.&lt;/p&gt;&#xA;&lt;h2 id=&#34;das-setup&#34;&gt;Das Setup&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Ein VPS bei Hetzner,&lt;/strong&gt; mit mehr CPU und Arbeitsspeicher, als meine Apps brauchen.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Caddy davor.&lt;/strong&gt; Caddy ist ein Webserver, der TLS-Zertifikate selbst holt und erneuert. Er leitet jede Domain an die richtige App weiter. Statische Websites sind Ordner, die Caddy direkt ausliefert.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Docker Compose für die Apps.&lt;/strong&gt; Jede App ist ein Container mit zwei Ordnern vom Host: einer für die SQLite-Datenbank, einer für hochgeladene und erzeugte Dateien. Der ganze Zustand liegt in diesen zwei Ordnern.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Cloudflare vor allem,&lt;/strong&gt; für DNS und Caching.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;wie-ein-deploy-abläuft&#34;&gt;Wie ein Deploy abläuft&lt;/h2&gt;&#xA;&lt;p&gt;Ein Push auf &lt;code&gt;master&lt;/code&gt; startet die Pipeline auf einem selbst gehosteten GitHub-Runner. Sie lintet den Code, baut ein Docker-Image und versieht es mit dem Commit-Hash. Dann kopiert sie eine Compose-Datei mit genau diesem Tag auf den Server und führt &lt;code&gt;docker compose pull &amp;amp;&amp;amp; docker compose up -d&lt;/code&gt; aus.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Ein neuer Rechner braucht Docker und sonst nichts</title>
      <link>https://panzeri.rocks/de/writing/docker-only-dev-loop/</link>
      <pubDate>Thu, 30 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/docker-only-dev-loop/</guid>
      <description>&lt;p&gt;Teil acht des Boring Stack. Die App ist &lt;a href=&#34;https://panzeri.rocks/de/writing/why-go/&#34;&gt;Go&lt;/a&gt;, und &lt;a href=&#34;https://panzeri.rocks/de/writing/html-from-the-server/&#34;&gt;templ und Tailwind&lt;/a&gt; erzeugen Code und CSS. Das sind drei Toolchains, bevor man eine Zeile schreibt. Dieser Text handelt davon, wie ich sie von meinem Rechner fernhalte.&lt;/p&gt;&#xA;&lt;p&gt;Jedes Projekt, das ich baue, hat einen einzigen unterstützten Weg, es in der Entwicklung zu starten:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;task dev&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Das führt &lt;code&gt;docker compose up --build&lt;/code&gt; aus. Dann öffne ich die App im Browser und fange an.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Tests ohne Mocks</title>
      <link>https://panzeri.rocks/de/writing/tests-without-mocks/</link>
      <pubDate>Thu, 02 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/tests-without-mocks/</guid>
      <description>&lt;p&gt;Teil sieben des Boring Stack. Die &lt;a href=&#34;https://panzeri.rocks/de/writing/sqlite-is-enough/&#34;&gt;Datenbank ist SQLite&lt;/a&gt;, und das &lt;a href=&#34;https://panzeri.rocks/de/writing/migrations-in-the-binary/&#34;&gt;Schema migriert sich selbst&lt;/a&gt;. Das macht die Entscheidung beim Testen einfach.&lt;/p&gt;&#xA;&lt;p&gt;Ein verbreiteter Weg, einen Service zu testen, ist, seine Datenbank durch einen Mock zu ersetzen: ein falsches Objekt, das zurückgibt, was der Test ihm sagt. Der Test prüft dann, ob der Service das falsche Objekt mit den richtigen Argumenten aufgerufen hat.&lt;/p&gt;&#xA;&lt;p&gt;Dieser Test beweist, dass der Service eine Funktion aufruft. Er beweist nicht, dass die Abfrage funktioniert, dass die Spalte existiert, dass der Constraint das Einfügen erlaubt oder dass das Ergebnis in der erwarteten Reihenfolge zurückkommt. Genau diese Fehler sollen Tests finden.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Das Binary migriert seine Datenbank selbst</title>
      <link>https://panzeri.rocks/de/writing/migrations-in-the-binary/</link>
      <pubDate>Thu, 04 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/migrations-in-the-binary/</guid>
      <description>&lt;p&gt;Teil sechs des Boring Stack. Die App &lt;a href=&#34;https://panzeri.rocks/de/writing/hand-written-sql/&#34;&gt;schreibt ihr SQL selbst&lt;/a&gt;. Die Tabellen, gegen die dieses SQL läuft, ändern sich mit der Zeit, und diese Änderungen brauchen einen Ablauf.&lt;/p&gt;&#xA;&lt;p&gt;Der klassische Ablauf hat einen eigenen Schritt: Vor oder nach dem Deploy lässt jemand das Migrationswerkzeug gegen die Produktionsdatenbank laufen. Manchmal vergisst dieser Jemand es. Dann läuft neuer Code gegen ein altes Schema oder alter Code gegen ein neues.&lt;/p&gt;&#xA;&lt;p&gt;In meinen Apps gibt es diesen Schritt nicht. Das Binary migriert seine Datenbank beim Start selbst.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Das SQL, das man liest, ist das SQL, das läuft</title>
      <link>https://panzeri.rocks/de/writing/hand-written-sql/</link>
      <pubDate>Thu, 07 May 2026 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/hand-written-sql/</guid>
      <description>&lt;p&gt;Teil fünf des Boring Stack. Die Daten liegen in &lt;a href=&#34;https://panzeri.rocks/de/writing/sqlite-is-enough/&#34;&gt;SQLite&lt;/a&gt;. Dieser Text handelt vom Code zwischen App und Datenbank.&lt;/p&gt;&#xA;&lt;p&gt;Die übliche Wahl ist ein ORM: Man beschreibt seine Tabellen als Klassen oder Structs, und die Bibliothek schreibt das SQL. Das fühlt sich produktiv an bis zur ersten langsamen Seite, wenn man herausfinden muss, welche der vierzig erzeugten Abfragen das Problem ist und wie man das ORM dazu bringt, eine andere zu erzeugen.&lt;/p&gt;</description>
    </item>
    <item>
      <title>SQLite reicht</title>
      <link>https://panzeri.rocks/de/writing/sqlite-is-enough/</link>
      <pubDate>Thu, 09 Apr 2026 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/sqlite-is-enough/</guid>
      <description>&lt;p&gt;Teil vier des Boring Stack. Die App ist &lt;a href=&#34;https://panzeri.rocks/de/writing/why-go/&#34;&gt;in Go geschrieben&lt;/a&gt; und &lt;a href=&#34;https://panzeri.rocks/de/writing/html-from-the-server/&#34;&gt;rendert HTML auf dem Server&lt;/a&gt;. Jetzt muss sie ihre Daten irgendwo ablegen.&lt;/p&gt;&#xA;&lt;p&gt;Die Standardantwort ist Postgres. Eine ausgezeichnete Datenbank, die ich jahrelang benutzt habe. Für die Apps, die ich heute baue, nehme ich SQLite.&lt;/p&gt;&#xA;&lt;h2 id=&#34;eine-datenbank-die-eine-datei-ist&#34;&gt;Eine Datenbank, die eine Datei ist&lt;/h2&gt;&#xA;&lt;p&gt;SQLite ist kein Server. Es ist eine Bibliothek, die eine einzige Datei liest und schreibt. Die App öffnet &lt;code&gt;./data/app.db&lt;/code&gt;, und das ist die ganze Datenbank.&lt;/p&gt;</description>
    </item>
    <item>
      <title>HTML vom Server</title>
      <link>https://panzeri.rocks/de/writing/html-from-the-server/</link>
      <pubDate>Thu, 12 Mar 2026 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/html-from-the-server/</guid>
      <description>&lt;p&gt;Teil drei des Boring Stack. Nach der &lt;a href=&#34;https://panzeri.rocks/de/writing/why-go/&#34;&gt;Sprache&lt;/a&gt; und dem &lt;a href=&#34;https://panzeri.rocks/de/writing/just-net-http/&#34;&gt;Router&lt;/a&gt; kommt die grösste Entscheidung: was im Browser läuft.&lt;/p&gt;&#xA;&lt;p&gt;Der Standard für eine Web-App sind heute zwei Anwendungen. Ein Backend, das JSON liefert, und ein Frontend in React oder Vue, das aus diesem JSON eine Oberfläche macht. Zwei Codebasen, zwei Build-Pipelines, zwei Sätze Abhängigkeiten und dazwischen ein API-Vertrag, den beide Seiten synchron halten müssen.&lt;/p&gt;&#xA;&lt;p&gt;Für die Apps, die ich baue (Formulare, Listen, Dashboards, Verwaltungsmasken), ist das eine Anwendung zu viel. Meine Apps rendern HTML auf dem Server und schicken es an den Browser. Drei Werkzeuge machen das angenehm.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kein Router-Framework</title>
      <link>https://panzeri.rocks/de/writing/just-net-http/</link>
      <pubDate>Thu, 12 Feb 2026 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/just-net-http/</guid>
      <description>&lt;p&gt;Teil zwei des Boring Stack. In &lt;a href=&#34;https://panzeri.rocks/de/writing/why-go/&#34;&gt;Teil eins&lt;/a&gt; ging es um die Sprache. In diesem geht es um die erste Abhängigkeit, die die meisten Go-Web-Apps dazunehmen, und warum ich es nicht tue.&lt;/p&gt;&#xA;&lt;p&gt;Jahrelang war das Erste in einem Go-Webprojekt die Wahl eines Routers: gorilla/mux, chi, Gin, Echo. Der Standard-&lt;code&gt;http.ServeMux&lt;/code&gt; konnte weder nach HTTP-Methode unterscheiden noch Parameter aus dem Pfad lesen, also brauchte man etwas darüber.&lt;/p&gt;&#xA;&lt;p&gt;Mit Go 1.22 hat sich das geändert. Seither kann die Standardbibliothek beides:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go, weil es sich in fünf Jahren noch gleich liest</title>
      <link>https://panzeri.rocks/de/writing/why-go/</link>
      <pubDate>Thu, 15 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/why-go/</guid>
      <description>&lt;p&gt;Das ist der erste von zehn Texten über die Entscheidungen dahinter, wie ich Software baue. Jede hat eine Zeile auf meiner &lt;a href=&#34;https://panzeri.rocks/de/stack/&#34;&gt;Stack-Seite&lt;/a&gt;, und jede ist mit Absicht langweilig. Die erste Entscheidung ist die, von der alles andere abhängt: die Sprache.&lt;/p&gt;&#xA;&lt;p&gt;Ich baue in Go.&lt;/p&gt;&#xA;&lt;h2 id=&#34;was-ich-von-einer-sprache-brauche&#34;&gt;Was ich von einer Sprache brauche&lt;/h2&gt;&#xA;&lt;p&gt;Ich leite beruflich eine IT und schreibe Software am Abend und am Wochenende. Das bestimmt, was ich brauche. Ein Projekt bleibt vielleicht drei Monate liegen. Wenn ich zurückkomme, muss ich es in Minuten verstehen, sicher ändern und noch am selben Abend ausliefern.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Ready und Done</title>
      <link>https://panzeri.rocks/de/writing/ready-and-done/</link>
      <pubDate>Thu, 11 Dec 2025 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/ready-and-done/</guid>
      <description>&lt;p&gt;Der zehnte und letzte Teil der &lt;a href=&#34;https://panzeri.rocks/de/writing/product-owner-toolbox/&#34;&gt;Werkzeugkiste des Product Owners&lt;/a&gt;. Der &lt;a href=&#34;https://panzeri.rocks/de/writing/owning-the-backlog/&#34;&gt;Backlog des Ferientools ist priorisiert&lt;/a&gt;. Bleiben zwei Checklisten, eine an jedem Ende des Sprints.&lt;/p&gt;&#xA;&#xA;&lt;figure class=&#34;diagram&#34;&gt;&#xA;  &lt;div class=&#34;diagram-scroll&#34;&gt;&lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 680 220&#34; role=&#34;img&#34; aria-label=&#34;Ein Eintrag passiert die Definition of Ready auf dem Weg vom Product Backlog in den Sprint Backlog und die Definition of Done auf dem Weg vom Sprint ins Inkrement.&#34;&gt;&#xA;  &lt;g class=&#34;t-label&#34; text-anchor=&#34;middle&#34;&gt;&#xA;    &lt;text x=&#34;55&#34; y=&#34;34&#34;&gt;Backlog&lt;/text&gt;&#xA;    &lt;text x=&#34;255&#34; y=&#34;34&#34;&gt;Sprint backlog&lt;/text&gt;&#xA;    &lt;text x=&#34;400&#34; y=&#34;34&#34;&gt;Sprint&lt;/text&gt;&#xA;    &lt;text x=&#34;600&#34; y=&#34;34&#34;&gt;Inkrement&lt;/text&gt;&#xA;  &lt;/g&gt;&#xA;  &lt;g class=&#34;t-small&#34; font-weight=&#34;700&#34; text-anchor=&#34;middle&#34;&gt;&#xA;    &lt;text x=&#34;160&#34; y=&#34;14&#34;&gt;Definition&lt;/text&gt;&lt;text x=&#34;160&#34; y=&#34;29&#34;&gt;of Ready&lt;/text&gt;&#xA;    &lt;text x=&#34;500&#34; y=&#34;14&#34;&gt;Definition&lt;/text&gt;&lt;text x=&#34;500&#34; y=&#34;29&#34;&gt;of Done&lt;/text&gt;&#xA;  &lt;/g&gt;&#xA;  &lt;g class=&#34;field&#34;&gt;&#xA;    &lt;rect x=&#34;0&#34; y=&#34;52&#34; width=&#34;110&#34; height=&#34;16&#34;/&gt;&#xA;    &lt;rect x=&#34;0&#34; y=&#34;72&#34; width=&#34;110&#34; height=&#34;16&#34;/&gt;&#xA;    &lt;rect x=&#34;0&#34; y=&#34;92&#34; width=&#34;110&#34; height=&#34;16&#34;/&gt;&#xA;    &lt;rect x=&#34;0&#34; y=&#34;112&#34; width=&#34;110&#34; height=&#34;16&#34;/&gt;&#xA;    &lt;rect x=&#34;0&#34; y=&#34;132&#34; width=&#34;110&#34; height=&#34;16&#34;/&gt;&#xA;  &lt;/g&gt;&#xA;  &lt;g class=&#34;ink&#34;&gt;&#xA;    &lt;rect x=&#34;210&#34; y=&#34;72&#34; width=&#34;90&#34; height=&#34;16&#34;/&gt;&#xA;    &lt;rect x=&#34;210&#34; y=&#34;92&#34; width=&#34;90&#34; height=&#34;16&#34;/&gt;&#xA;    &lt;rect x=&#34;210&#34; y=&#34;112&#34; width=&#34;90&#34; height=&#34;16&#34;/&gt;&#xA;  &lt;/g&gt;&#xA;  &lt;rect class=&#34;signal&#34; x=&#34;155&#34; y=&#34;44&#34; width=&#34;10&#34; height=&#34;112&#34;/&gt;&#xA;  &lt;rect class=&#34;signal&#34; x=&#34;495&#34; y=&#34;44&#34; width=&#34;10&#34; height=&#34;112&#34;/&gt;&#xA;  &lt;circle class=&#34;stroke&#34; cx=&#34;400&#34; cy=&#34;100&#34; r=&#34;46&#34;/&gt;&#xA;  &lt;polygon class=&#34;ink&#34; points=&#34;396,48 396,60 408,54&#34;/&gt;&#xA;  &lt;text class=&#34;t-small t-muted&#34; x=&#34;400&#34; y=&#34;104&#34; text-anchor=&#34;middle&#34;&gt;1–4 Wochen&lt;/text&gt;&#xA;  &lt;rect class=&#34;ink&#34; x=&#34;550&#34; y=&#34;50&#34; width=&#34;100&#34; height=&#34;100&#34;/&gt;&#xA;  &lt;path class=&#34;stroke&#34; d=&#34;M116 100H143 M170 100H198 M305 100H340 M447 100H483 M510 100H538&#34;/&gt;&#xA;  &lt;g class=&#34;ink&#34;&gt;&#xA;    &lt;polygon points=&#34;141,94 141,106 151,100&#34;/&gt;&#xA;    &lt;polygon points=&#34;196,94 196,106 206,100&#34;/&gt;&#xA;    &lt;polygon points=&#34;338,94 338,106 348,100&#34;/&gt;&#xA;    &lt;polygon points=&#34;481,94 481,106 491,100&#34;/&gt;&#xA;    &lt;polygon points=&#34;536,94 536,106 546,100&#34;/&gt;&#xA;  &lt;/g&gt;&#xA;  &lt;g class=&#34;t-small t-muted&#34; text-anchor=&#34;middle&#34;&gt;&#xA;    &lt;text x=&#34;160&#34; y=&#34;184&#34;&gt;Klar genug,&lt;/text&gt;&lt;text x=&#34;160&#34; y=&#34;200&#34;&gt;um anzufangen?&lt;/text&gt;&#xA;    &lt;text x=&#34;500&#34; y=&#34;184&#34;&gt;Gut genug,&lt;/text&gt;&lt;text x=&#34;500&#34; y=&#34;200&#34;&gt;um auszuliefern?&lt;/text&gt;&#xA;  &lt;/g&gt;&#xA;&lt;/svg&gt;&#xA;&lt;/div&gt;&#xA;  &lt;figcaption&gt;Zwei Prüfungen, eine an jedem Ende des Sprints.&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&#xA;&lt;h2 id=&#34;definition-of-ready&#34;&gt;Definition of Ready&lt;/h2&gt;&#xA;&lt;p&gt;Die Definition of Ready ist eine Checkliste mit Kriterien, die ein Backlog-Eintrag erfüllen muss, bevor er vom Product Backlog in einen Sprint Backlog wechseln darf.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Den Backlog verantworten</title>
      <link>https://panzeri.rocks/de/writing/owning-the-backlog/</link>
      <pubDate>Thu, 27 Nov 2025 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/owning-the-backlog/</guid>
      <description>&lt;p&gt;Teil neun der &lt;a href=&#34;https://panzeri.rocks/de/writing/product-owner-toolbox/&#34;&gt;Werkzeugkiste des Product Owners&lt;/a&gt;. Wir sind von der &lt;a href=&#34;https://panzeri.rocks/de/writing/product-vision/&#34;&gt;Vision&lt;/a&gt; bis zu &lt;a href=&#34;https://panzeri.rocks/de/writing/splitting-stories/&#34;&gt;kleinen Stories&lt;/a&gt; gekommen. Alle landen am selben Ort.&lt;/p&gt;&#xA;&lt;p&gt;Der Product Owner, und nur der Product Owner, verwaltet den Product Backlog. Er ist dafür verantwortlich, dass der Backlog aktuell ist, und entscheidet, was gebaut wird und was nicht. Er sorgt dafür, dass die Sicht der Kunden in den Backlog einfliesst und der Backlog auf Wert ausgerichtet bleibt. Und er sorgt dafür, dass der Backlog priorisiert und aktuell ist und dass die Meetings und die Arbeit, die es dafür braucht, auch stattfinden.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Stories dünner schneiden</title>
      <link>https://panzeri.rocks/de/writing/splitting-stories/</link>
      <pubDate>Thu, 06 Nov 2025 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/splitting-stories/</guid>
      <description>&lt;p&gt;Teil acht der &lt;a href=&#34;https://panzeri.rocks/de/writing/product-owner-toolbox/&#34;&gt;Werkzeugkiste des Product Owners&lt;/a&gt;. Im &lt;a href=&#34;https://panzeri.rocks/de/writing/a-story-is-a-promise/&#34;&gt;letzten Teil&lt;/a&gt; haben wir eine gute User Story geschrieben. Die meisten Stories fangen nicht so gut an. Sie fangen zu gross an.&lt;/p&gt;&#xA;&lt;p&gt;Schneiden heisst, eine Story in kleinere, in sich stimmige Stücke zu teilen, die sich schätzen, bauen und testen lassen, alles innerhalb eines Sprints. Die Gründe sind verschieden: die Kapazität des Sprints, die Komplexität der Story, ein Teil davon, der noch unklar ist.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Eine User Story ist ein Versprechen, miteinander zu reden</title>
      <link>https://panzeri.rocks/de/writing/a-story-is-a-promise/</link>
      <pubDate>Thu, 16 Oct 2025 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/a-story-is-a-promise/</guid>
      <description>&lt;p&gt;Teil sieben der &lt;a href=&#34;https://panzeri.rocks/de/writing/product-owner-toolbox/&#34;&gt;Werkzeugkiste des Product Owners&lt;/a&gt;. Die &lt;a href=&#34;https://panzeri.rocks/de/writing/features-and-story-maps/&#34;&gt;Story Map&lt;/a&gt; des Ferientools ist voller Karten. Jetzt schauen wir uns eine einzelne an.&lt;/p&gt;&#xA;&lt;p&gt;Eine User Story beschreibt eine Funktionalität aus der Sicht eines bestimmten Nutzers. Meistens wird sie in normaler Sprache nach einer festen Vorlage geschrieben und ist bewusst kurz:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;Als&lt;/strong&gt; (Rolle oder Persona)&#xA;&lt;strong&gt;will ich&lt;/strong&gt; (Ziel oder Funktion),&#xA;&lt;strong&gt;damit&lt;/strong&gt; (der Nutzen).&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Die Vorlage ist das Unwichtigste daran. Sie hilft, den Nutzer im Blick zu behalten, aber entscheidend ist, ob das Team vier Fragen beantworten kann: Warum bauen wir das? Für wen? Welches Problem löst es? Und wie bauen wir es technisch?&lt;/p&gt;</description>
    </item>
    <item>
      <title>Von der Journey zur Story Map</title>
      <link>https://panzeri.rocks/de/writing/features-and-story-maps/</link>
      <pubDate>Thu, 25 Sep 2025 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/features-and-story-maps/</guid>
      <description>&lt;p&gt;Teil sechs der &lt;a href=&#34;https://panzeri.rocks/de/writing/product-owner-toolbox/&#34;&gt;Werkzeugkiste des Product Owners&lt;/a&gt;. Für das Ferientool haben wir ein &lt;a href=&#34;https://panzeri.rocks/de/writing/epics-are-bets/&#34;&gt;Epic&lt;/a&gt; und eine &lt;a href=&#34;https://panzeri.rocks/de/writing/personas-and-journeys/&#34;&gt;User Journey&lt;/a&gt;. Jetzt verbinden wir die beiden.&lt;/p&gt;&#xA;&lt;h2 id=&#34;features&#34;&gt;Features&lt;/h2&gt;&#xA;&lt;p&gt;Ein Feature ist eine Funktionalität oder ein Teil einer User Journey, aus der Sicht einer bestimmten Nutzergruppe. Es liefert einen Wert, der die Bedürfnisse dieser Gruppe erfüllt. Ein Feature wird über mehrere User Stories umgesetzt, die aus Sicht der Nutzer zusammengehören. Es dauert länger als einen Sprint und passt in ein Release.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Für wen ist das?</title>
      <link>https://panzeri.rocks/de/writing/personas-and-journeys/</link>
      <pubDate>Thu, 11 Sep 2025 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/personas-and-journeys/</guid>
      <description>&lt;p&gt;Teil fünf der &lt;a href=&#34;https://panzeri.rocks/de/writing/product-owner-toolbox/&#34;&gt;Werkzeugkiste des Product Owners&lt;/a&gt;. Das Ferientool hat eine &lt;a href=&#34;https://panzeri.rocks/de/writing/product-vision/&#34;&gt;Vision&lt;/a&gt; und ein erstes &lt;a href=&#34;https://panzeri.rocks/de/writing/epics-are-bets/&#34;&gt;Epic&lt;/a&gt;. Bevor wir das Epic in Features herunterbrechen, müssen wir die Menschen kennen, für die wir es bauen.&lt;/p&gt;&#xA;&lt;h2 id=&#34;personas&#34;&gt;Personas&lt;/h2&gt;&#xA;&lt;p&gt;Eine Persona ist ein erfundenes, aber konkretes Mitglied einer Nutzergruppe, mit persönlichen Merkmalen, Absichten und Gefühlen.&lt;/p&gt;&#xA;&lt;p&gt;Gute Personas entstehen aus Daten. Du sammelst sie mit Interviews oder Fragebögen, gruppierst sie mit einer Segmentierung oder Clusteranalyse und verdichtest jede Gruppe zu einer Persona. Eine Persona, die in einem Workshop von Leuten erfunden wurde, die nie einen Nutzer getroffen haben, ist ein Klischee mit Namen. Das ist schlimmer als gar keine Persona, weil es wie ein Beleg aussieht.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Epics sind Wetten</title>
      <link>https://panzeri.rocks/de/writing/epics-are-bets/</link>
      <pubDate>Thu, 28 Aug 2025 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/epics-are-bets/</guid>
      <description>&lt;p&gt;Teil vier der &lt;a href=&#34;https://panzeri.rocks/de/writing/product-owner-toolbox/&#34;&gt;Werkzeugkiste des Product Owners&lt;/a&gt;. Das Ferientool hat jetzt eine &lt;a href=&#34;https://panzeri.rocks/de/writing/product-vision/&#34;&gt;Vision&lt;/a&gt;. Als Nächstes kommt das erste grosse Stück Arbeit.&lt;/p&gt;&#xA;&lt;p&gt;Ein Epic beschreibt ein grosses Bedürfnis oder Problem: so gross, dass seine Lösung eine echte Investition ist, oft so gross, dass es einen schlanken Business Case braucht. Es ist die grösste Art von Backlog-Eintrag und sollte leicht verständlich sein. Es sagt grob, &lt;em&gt;warum&lt;/em&gt; etwas gelöst werden soll und &lt;em&gt;was&lt;/em&gt;, mehr nicht.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Von Air zu Watchexec</title>
      <link>https://panzeri.rocks/de/writing/from-air-to-watchexec/</link>
      <pubDate>Mon, 18 Aug 2025 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/from-air-to-watchexec/</guid>
      <description>&lt;p&gt;Als Entwickler sind wir Gewohnheitstiere. Wir finden Werkzeuge, die funktionieren, und bleiben bei ihnen, manchmal weit über ihr Ablaufdatum hinaus. Jahrelang habe ich beim Hot Reloading auf Air für Go geschworen. Es war einfach, es funktionierte (meistens), und meine Go-Projekte liefen damit rund. Aber wie in vielen langen Beziehungen wurde aus Bequemlichkeit irgendwann ein Kompromiss.&lt;/p&gt;&#xA;&lt;p&gt;Der Wendepunkt kam, als ich mehr mit Projekten aus mehreren Modulen und gemeinsamen Bibliotheken arbeitete. Plötzlich waren die Grenzen von Air keine kleinen Ärgernisse mehr, sie haben meine Produktivität aufgefressen.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Eine Vision, mit der man Nein sagen kann</title>
      <link>https://panzeri.rocks/de/writing/product-vision/</link>
      <pubDate>Thu, 07 Aug 2025 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/product-vision/</guid>
      <description>&lt;p&gt;Teil drei der &lt;a href=&#34;https://panzeri.rocks/de/writing/product-owner-toolbox/&#34;&gt;Werkzeugkiste des Product Owners&lt;/a&gt;. Im &lt;a href=&#34;https://panzeri.rocks/de/writing/just-in-time-specification/&#34;&gt;letzten Teil&lt;/a&gt; hing am Ende jeder Backlog-Eintrag an einer Vision. Jetzt brauchen wir eine.&lt;/p&gt;&#xA;&lt;p&gt;Eine Produktvision beschreibt in einer kurzen Aussage, warum es ein Produkt gibt, für wen es ist und was es besser macht als die Alternativen. Sie ist langfristig. Sie gibt allen, die am Produkt arbeiten, eine Richtung und etwas, woran sie ihre Arbeit messen können. Jeder Backlog-Eintrag, auf jeder Ebene, sollte das Produkt näher an sie heranbringen.&lt;/p&gt;</description>
    </item>
    <item>
      <title>APIs sind nicht optional</title>
      <link>https://panzeri.rocks/de/writing/apis-are-not-optional/</link>
      <pubDate>Thu, 31 Jul 2025 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/apis-are-not-optional/</guid>
      <description>&lt;p&gt;Moderne Anwendungsentwicklung fühlt sich oft wie ein Rennen an. Schneller bauen. Früher ausliefern. Ständig iterieren. In dieser Eile bieten Plattformen wie Firebase und Supabase eine verlockende Abkürzung: Sie versprechen, dass du dich nicht um die Backend-Infrastruktur kümmern musst. Einfach die App direkt mit der Datenbank verbinden, ein paar Regeln darüberlegen, fertig.&lt;/p&gt;&#xA;&lt;p&gt;Diese Denkweise hat aber einen grundlegenden Fehler, und der ist nicht nur theoretisch. Echte Firmen und echte Nutzer lernen ihn gerade auf die harte Tour.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Just in Time spezifizieren</title>
      <link>https://panzeri.rocks/de/writing/just-in-time-specification/</link>
      <pubDate>Thu, 24 Jul 2025 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/just-in-time-specification/</guid>
      <description>&lt;p&gt;Das ist der zweite Teil der &lt;a href=&#34;https://panzeri.rocks/de/writing/product-owner-toolbox/&#34;&gt;Werkzeugkiste des Product Owners&lt;/a&gt;. Das durchgehende Beispiel ist ein Tool, das die Tabelle ersetzt, in der eine Firma mit 300 Leuten ihre Ferienanträge verwaltet.&lt;/p&gt;&#xA;&lt;p&gt;Früher hätte man für das Ferientool zuerst ein Pflichtenheft geschrieben: vierzig Seiten über jede Abwesenheitsart, jeden Bewilligungsweg und jeden Sonderfall rund um den Jahreswechsel, unterschrieben, bevor jemand eine Zeile Code schreibt.&lt;/p&gt;&#xA;&lt;p&gt;Das scheitert auf zwei Arten, und beide kosten Geld.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Der Inhalt veraltet.&lt;/strong&gt; Anforderungen ändern sich, während man sie aufschreibt, und das Umfeld ändert sich mit. Bis die Entwicklung bei Seite 30 ankommt, beschreibt Seite 30 ein Bedürfnis, das es nicht mehr gibt. Das Schreiben war verlorene Arbeit, das Nachführen ist noch mehr davon.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Die Werkzeugkiste des Product Owners</title>
      <link>https://panzeri.rocks/de/writing/product-owner-toolbox/</link>
      <pubDate>Thu, 10 Jul 2025 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/product-owner-toolbox/</guid>
      <description>&lt;p&gt;Ich war mehr als vier Jahre Product Owner: zuerst für die TV-Produkte von Quickline, dann bei localsearch, dann als Head of Product Owners bei Lifestage, bevor ich die IT übernommen habe. Heute sitze ich auf der anderen Seite des Tisches. Ich arbeite mit Product Owners, ich stelle sie ein, und ab und zu muss ich erklären, warum ein Team mit vollem Backlog trotzdem nichts liefert, was zählt.&lt;/p&gt;&#xA;&lt;p&gt;Selten fehlt dafür eine Methode. Meistens sind alle Methoden da, nur weiss niemand mehr, wofür. Die User-Story-Vorlage ist perfekt ausgefüllt, es gibt eine Definition of Ready, die niemand liest, und im Backlog liegen 600 Einträge, die niemand übers Herz bringt zu löschen.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Mit Ubuntu Cloud Images arbeiten</title>
      <link>https://panzeri.rocks/de/writing/work-with-ubuntu-cloud-images/</link>
      <pubDate>Sat, 23 Mar 2024 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/work-with-ubuntu-cloud-images/</guid>
      <description>&lt;aside class=&#34;update-note&#34; role=&#34;note&#34;&gt;&#xA;  &lt;p class=&#34;update-note-label&#34;&gt;Aktualisiert am 11. Oktober 2026&lt;/p&gt;&#xA;  &lt;p&gt;Neu geschrieben, damit die Anleitung dem aktuellen Stand von Linux entspricht: Sie verwendet jetzt Ubuntu 24.04 LTS und führt von der Installation von KVM bis zur laufenden VM.&lt;/p&gt;&#xA;&#xA;&lt;/aside&gt;&#xA;&#xA;&lt;p&gt;Ubuntu von einer ISO-Datei zu installieren heisst, sich jedes Mal durch einen Installer zu klicken. Die Cloud Images von Ubuntu ersparen das. Sie sind vorinstallierte Disk-Images, dieselben, die Cloud-Anbieter starten, und sie richten sich beim ersten Start mit cloud-init selbst ein: Hostname, Benutzer, SSH-Schlüssel, Pakete.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Platz von einer vergrösserten physischen (oder virtuellen) Disk nutzen</title>
      <link>https://panzeri.rocks/de/writing/use-space-from-extended-disk/</link>
      <pubDate>Wed, 13 Mar 2024 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/use-space-from-extended-disk/</guid>
      <description>&lt;p&gt;Zuerst musst du die Disk vergrössern, die Linux zur Verfügung gestellt wird. Meistens erweiterst du dafür die virtuelle Disk in KVM, VMware oder Hyper-V oder vergrösserst das Volume im RAID-Controller oder Speichersystem. Das geht oft, während Linux läuft, ohne Herunterfahren oder Neustart. Für mein Beispiel habe ich eine Disk von 100 GB auf 200 GB erweitert.&lt;/p&gt;&#xA;&lt;p&gt;Danach musst du Linux eventuell dazu bringen, die Disk neu nach freiem Platz abzusuchen. Starte &lt;code&gt;cfdisk&lt;/code&gt; und prüf, ob freier Platz angezeigt wird. Mit «q» verlässt du das Programm wieder.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Snap ein für alle Mal entfernen</title>
      <link>https://panzeri.rocks/de/writing/remove-snap-once-and-forever/</link>
      <pubDate>Thu, 07 Mar 2024 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/remove-snap-once-and-forever/</guid>
      <description>&lt;h2 id=&#34;warum-man-snap-nicht-verwenden-sollte&#34;&gt;Warum man Snap nicht verwenden sollte&lt;/h2&gt;&#xA;&lt;p&gt;Ob man Snap aus Ubuntu entfernt, hängt von persönlichen Vorlieben, den Ressourcen des Systems oder dem konkreten Einsatzzweck ab. Das sind einige Gründe, warum jemand Snap entfernen möchte:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Ressourcenverbrauch:&#xA;Snap-Pakete können mehr Speicherplatz belegen als klassische Debian-Pakete. Manche Nutzer, vor allem mit wenig Speicher, entfernen Snap, um Ressourcen zu sparen.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Performance:&#xA;Snap-Pakete haben den Vorteil, dass sie in einer Sandbox laufen und alles mitbringen. Manche Nutzer sind aber der Meinung, dass klassische Paketverwaltungen schneller sind und Anwendungen schneller starten.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Doppelte Pakete:&#xA;Manchmal gibt es dieselbe Anwendung sowohl als Snap als auch als APT-Paket. Manche Nutzer bleiben lieber bei einem einzigen Paketsystem, um doppelte Installationen zu vermeiden.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Anpassung und Kontrolle:&#xA;Wer mehr Kontrolle über sein System will und bei den Paketen aus den offiziellen Ubuntu-Repositories bleiben möchte, entfernt Snap vielleicht. So bleibt die Paketverwaltung schlank und klassisch.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Sicherheit:&#xA;Snap-Pakete sind zwar mit Blick auf Sicherheit entworfen, aber manche Nutzer haben eigene Vorstellungen oder Bedenken und wählen deshalb andere Paketformate.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Community und Lizenzen:&#xA;Ab und zu gibt es Bedenken der Community oder zu Lizenzen rund um das Snap-Format. Wer viel Wert auf Open-Source-Prinzipien legt, entfernt Snap vielleicht zugunsten anderer Paketformate.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Persönliche Vorliebe:&#xA;Am Ende ist es oft eine Frage des Geschmacks und davon, mit welchem Paketsystem man sich wohlfühlt. Manche mögen einfach die Vertrautheit und Einfachheit der klassischen Paketverwaltung.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;</description>
    </item>
    <item>
      <title>Selbst gehostete GitHub-Runner in Kubernetes</title>
      <link>https://panzeri.rocks/de/writing/self-hosted-github-runner-in-kubernetes/</link>
      <pubDate>Wed, 06 Mar 2024 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/self-hosted-github-runner-in-kubernetes/</guid>
      <description>&lt;aside class=&#34;update-note&#34; role=&#34;note&#34;&gt;&#xA;  &lt;p class=&#34;update-note-label&#34;&gt;Aktualisiert am 11. Oktober 2026&lt;/p&gt;&#xA;  &lt;p&gt;Neu geschrieben, damit die Anleitung dem aktuellen Stand von Linux und Kubernetes entspricht: Sie verwendet jetzt die Runner Scale Sets, die GitHub selbst pflegt, statt des älteren Community-Controllers.&lt;/p&gt;&#xA;&#xA;&lt;/aside&gt;&#xA;&#xA;&lt;p&gt;Die von GitHub gehosteten Runner sind bequem, aber sie werden pro Minute abgerechnet, erreichen nichts in deinem Netzwerk und starten jedes Mal auf einer leeren Maschine. Wenn du schon einen Kubernetes-Cluster betreibst, kannst du die Jobs dort laufen lassen. Actions Runner Controller (ARC) startet für jeden Job einen frischen Runner-Pod und entfernt ihn danach wieder.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kubernetes auf Bare Metal</title>
      <link>https://panzeri.rocks/de/writing/kubernetes-on-bare-metal/</link>
      <pubDate>Wed, 06 Mar 2024 00:00:00 +0000</pubDate>
      <guid>https://panzeri.rocks/de/writing/kubernetes-on-bare-metal/</guid>
      <description>&lt;h2 id=&#34;voraussetzungen&#34;&gt;Voraussetzungen&lt;/h2&gt;&#xA;&lt;p&gt;Das sind die Mindestanforderungen, um einen Kubernetes-Cluster auf Bare Metal aufzusetzen:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Ein kompatibler Linux-Host. Das Kubernetes-Projekt stellt allgemeine Anleitungen für Debian- und Red-Hat-basierte Distributionen bereit, und für Distributionen ohne Paketmanager.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Mindestens 2 GB RAM pro Maschine (mit weniger bleibt kaum Platz für deine Apps).&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Mindestens 2 CPUs pro Maschine.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Volle Netzwerkverbindung zwischen allen Maschinen im Cluster (öffentliches oder privates Netz spielt keine Rolle).&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Bestimmte Ports müssen auf deinen Maschinen offen sein. Details weiter unten.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;</description>
    </item>
  </channel>
</rss>
