Eliminierung technischer Schulden mit PHPStan, Rector PHP und PHPUnit. Über 20 Jahre Praxiserfahrung in skalierbaren Backends.
- Aktualisiert:
- Autor:
- Roland Golla
Parallel Change: Definition
Parallel Change ist ein Muster, um nicht abwärtskompatible Änderungen an einer Schnittstelle sicher umzusetzen. Die Änderung wird in drei Phasen zerlegt: Expand, Migrate und Contract. Alte und neue Variante existieren dabei eine Zeit lang nebeneinander.
Danilo Sato beschrieb das Muster 2014 im Bliki von Martin Fowler, dokumentiert wurde die Technik zuvor von Joshua Kerievsky. Unter dem Namen Expand and Contract ist sie ebenfalls verbreitet. Der Kern ist simpel: Wer eine Methodensignatur, ein API Feld oder eine Datenbankspalte ändert, muss nicht gleichzeitig alle Aufrufer anpassen. Zuerst wird das Neue ergänzt, dann ziehen die Aufrufer nach, zuletzt fällt das Alte weg. Jede dieser Phasen ist für sich deploybar.
Inhalt
Parallel Change mit NCA: Schnelle Hilfe vom Experten
Schemaänderungen ohne Wartungsfenster gehören zu den Aufgaben, bei denen Erfahrung den Unterschied macht. Never Code Alone entwickelt seit über 20 Jahren mit Symfony und Doctrine, unser CMS läuft auf Sulu. Deployments laufen automatisiert über GitHub Actions und GitLab CI, abgesichert durch Tests und statische Analyse.
Wir begleiten Teams im PHP Consulting und beim Refactoring Workshop. Für Schemaänderungen nutzen wir Doctrine Migrations, für automatisierte Umbauten im Code Rector PHP. Ob wirklich alle Aufrufer umgestellt sind, prüfen PHPStan, Unused Public und Class Leak. Abgesichert wird mit PHPUnit und Functional Tests.
Lass uns sprechen
Finde das passende Angebot für dein Projekt
Anfrage-Konfiguration
Starten Sie Ihre Anfrage
Gesetzliche Konformität & Inklusion. Optimierung von Performance und Conversion durch radikal nutzerzentriertes, universelles Design.
Skalierbare KI-Systeme mit echtem Code Ownership. CI/CD, Backup-Strategien und Infrastruktur, die mit deinem Team wächst.
Anfrage-Konfiguration
Worauf liegt dein Fokus?
Wähle die Expertise, die dein Projekt jetzt am dringendsten benötigt.
Die drei Phasen
Expand. Die Schnittstelle wird erweitert, sodass sie alt und neu gleichzeitig beherrscht. Eine neue Methode kommt dazu, die alte bleibt unverändert. In der Datenbank entsteht eine neue Spalte, die alte bleibt bestehen. Bestehende Aufrufer merken von dieser Phase nichts.
Migrate. Die Aufrufer wechseln nacheinander auf die neue Variante. Bei internem Code ist das eine Frage von Tagen, bei externen Clients kann diese Phase Monate dauern. Sie lässt sich beliebig in kleine Schritte zerlegen, jeder davon ist einzeln deploybar.
Contract. Wenn kein Aufrufer mehr die alte Variante nutzt, wird sie entfernt. Erst jetzt verschwindet die alte Methode, erst jetzt fällt die alte Spalte weg. Danach ist die Schnittstelle wieder eindeutig.
Der Gewinn liegt darin, dass zu keinem Zeitpunkt ein Bruch entsteht. Zwischen Expand und Contract lässt sich jederzeit deployen, zurückrollen und pausieren. Genau das macht das Muster zur Grundlage für Continuous Delivery.
Expand, Migrate und Contract im Vergleich
| Phase | Im Code | In der Datenbank |
|---|---|---|
| Ausgangslage | Nur die alte Methode existiert | Nur die alte Spalte existiert |
| Expand | Neue Methode kommt dazu, alte bleibt | Neue Spalte kommt dazu, es wird doppelt geschrieben |
| Migrate | Aufrufer wechseln nach und nach | Altdaten werden in Blöcken nachgezogen und geprüft |
| Contract | Alte Methode wird entfernt | Lesezugriffe laufen neu, alte Spalte fällt weg |
Parallel Change in der Datenbank
Der häufigste Anwendungsfall in PHP Projekten ist die Datenbank. Ein Feld soll aufgeteilt, umbenannt oder in einen anderen Typ überführt werden, und die Anwendung darf dabei nicht stehen.
In der Expand Phase entsteht die neue Spalte über eine Migration. Wichtig ist, dass sie zunächst optional bleibt. Eine Spalte, die sofort not null ist, bricht jedes laufende Deployment, weil der alte Code sie nicht befüllt.
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE orders ADD delivery_country_iso VARCHAR(2) DEFAULT NULL');
}
Ab jetzt schreibt die Anwendung in beide Spalten. Die neue ist die Wahrheit für alles, was ab heute entsteht, die alte bleibt gefüllt, damit ein Rückrollen möglich bleibt. Gelesen wird weiterhin aus der alten Spalte.
In der Migrate Phase wandern die Altdaten nach. Nicht in einem einzigen Statement über Millionen Zeilen, sondern in Blöcken, damit die Datenbank ansprechbar bleibt. Nach jedem Block prüft ein Abgleich, ob alt und neu übereinstimmen. Erst wenn keine Zeile mehr offen ist, wechselt der Lesezugriff.
In der Contract Phase fällt die alte Spalte weg. Dieser Schritt wird gern vergessen. Ein Schema, in dem beide Spalten dauerhaft existieren, ist schlechter als der Zustand vorher, weil jetzt niemand mehr weiß, welche gilt.
Typische Fehler bei Parallel Change
Contract wird nie ausgeführt. Der mit Abstand häufigste Fehler. Expand und Migrate sind erledigt, dann kommt das nächste Thema. Zurück bleiben zwei Wege zum selben Ziel und niemand traut sich, einen davon zu löschen. Der Aufräumschritt gehört von Anfang an ins Ticket, nicht in eine Wunschliste.
Die neue Spalte ist sofort verpflichtend. Während des Deployments laufen alter und neuer Code kurzzeitig gleichzeitig. Eine Spalte ohne Standardwert, die not null ist, führt genau dort zu Fehlern. Erst optional anlegen, später verschärfen.
Altdaten in einem Rutsch migrieren. Ein Update über eine große Tabelle sperrt sie und legt die Anwendung lahm. In Blöcken arbeiten, Fortschritt festhalten, jederzeit fortsetzbar bleiben.
Kein Abgleich nach der Migration. Ohne Prüfung weiß niemand, ob wirklich alle Zeilen übernommen wurden. Ein Zähler auf beiden Seiten und eine Stichprobe auf Gleichheit kosten wenig und verhindern böse Überraschungen.
Die alte Variante wird nicht als veraltet markiert. Wer in der Migrate Phase keinen Hinweis hinterlässt, bekommt neue Aufrufer der alten Methode. Ein Deprecated Attribut und eine Notiz im Code halten die Richtung klar.
Wo Parallel Change sonst noch greift
Das Muster ist nicht auf Datenbanken beschränkt. Überall, wo eine Schnittstelle Konsumenten hat, funktioniert derselbe Dreischritt.
- Refactoring von Signaturen. Eine Methode bekommt einen anderen Parametertyp. Die alte Signatur bleibt und delegiert an die neue, bis alle Aufrufstellen umgestellt sind.
- REST APIs. Ein Antwortfeld ändert sich. Das neue Feld kommt zusätzlich in die Antwort, das alte bleibt. Clients ziehen in ihrem eigenen Tempo nach, danach fällt das alte Feld weg.
- Deployments. Blue Green Deployment und Canary Releases sind Anwendungen desselben Gedankens. Zwei Versionen laufen nebeneinander, der Verkehr wandert schrittweise.
- Konfiguration. Ein Parametername ändert sich. Beide werden eine Zeit lang akzeptiert, der alte erzeugt eine Warnung, später verschwindet er.
In der Migrate Phase hilft ein Feature Flag, um zwischen alter und neuer Variante umzuschalten, ohne neu zu deployen. Bei vielen gleichartigen Aufrufstellen im eigenen Code lohnt sich außerdem eine Regel in Rector: Der Umbau läuft dann automatisiert und einheitlich statt hunderte Male von Hand. Wie das im Zusammenspiel mit einer schrittweisen Ablösung aussieht, steht bei uns im Beitrag zum Rector PHP.
a pattern to implement backward-incompatible changes to an interface in a safe manner
Die NCA Erfahrung mit Schemaänderungen
Deployments ohne Wartungsfenster sind kein Luxus, sondern Voraussetzung dafür, dass ein Team überhaupt regelmäßig ausliefern kann. Parallel Change ist dabei das Muster, das die meisten Stichtage überflüssig macht.
Die Migrationen selbst laufen über Doctrine Migrations, ausgerollt mit PHP Deployer. Ob wirklich kein Aufrufer der alten Variante übrig ist, zeigen PHPStan, Unused Public und Class Leak. Massenhafte Umstellungen im Code übernimmt Rector PHP, die Typen prüft Type Coverage. Abgesichert wird mit PHPUnit, Symfony KernelTestCase und Cypress. Vor dem Commit hält GrumPHP die Qualität, im Betrieb sorgt das Monitoring für Sichtbarkeit.
Erreichen Sie unsere PHP Consultant Spezialisten
Wir sind Experten für PHP und helfen Ihnen, Ihre digitalen Herausforderungen zu meistern. Unser erfahrenes Team unterstützt Sie bei PHP Updates, PHP Refactoring und berät Sie remote zu allen Fragen rund um PHP. Mit unseren vollautomatischen CI/CD Deployments und einer robusten Docker-Infrastruktur bringen wir Ihre PHP-Projekte auf das nächste Level. Vertrauen Sie auf unsere Expertise für zuverlässige und skalierbare PHP-Lösungen.
Häufige Fragen zu Parallel Change
Was Teams fragen, bevor sie ein Schema im laufenden Betrieb ändern.
Was ist Parallel Change 2026 in einem Satz?
Ein Muster, um eine nicht abwärtskompatible Änderung an einer Schnittstelle in drei Phasen aufzuteilen. Erst wird das Neue ergänzt, dann ziehen die Aufrufer nach, zuletzt fällt das Alte weg. Jede Phase ist einzeln deploybar, dadurch entsteht zu keinem Zeitpunkt ein Bruch.
Ist Parallel Change 2026 dasselbe wie Expand and Contract?
Ja, das sind zwei Namen für dasselbe Muster. Danilo Sato beschrieb es 2014 im Bliki von Martin Fowler unter dem Namen Parallel Change und nennt Expand and Contract als geläufige Alternative. Dokumentiert wurde die Technik zuvor von Joshua Kerievsky als Refactoring Strategie.
Brauche ich Parallel Change 2026 auch bei internem Code?
Ja, obwohl man dort theoretisch alles auf einmal ändern könnte. Der Vorteil ist, dass ein Bruch nicht durch die gesamte Codebasis läuft. Die Migrate Phase darf bei internem Code kurz sein, oft nur ein Merge Request. Wichtig ist, dass Expand und Contract getrennte Schritte bleiben.
Wie lange darf die Migrate Phase 2026 dauern?
So kurz wie möglich, so lang wie nötig. Bei internem Code sind Tage realistisch, bei externen Clients Wochen oder Monate. Entscheidend ist ein festes Enddatum für Contract. Ohne diesen Termin bleibt die alte Variante dauerhaft bestehen, und die Codebasis wird komplizierter statt einfacher.
Wie ändere ich 2026 eine Spalte ohne Wartungsfenster?
Neue Spalte optional anlegen, ab sofort in beide schreiben, Altdaten in Blöcken nachziehen, Ergebnis abgleichen, dann Lesezugriffe umstellen und zuletzt die alte Spalte entfernen. Wichtig ist, dass die neue Spalte anfangs nicht verpflichtend ist, sonst bricht der alte Code während des Deployments.
Warum darf die neue Spalte nicht sofort not null sein?
Weil während eines Deployments für kurze Zeit alter und neuer Code parallel laufen. Der alte kennt die neue Spalte nicht und befüllt sie nicht. Eine Pflichtspalte ohne Standardwert führt dann zu Fehlern beim Einfügen. Die Verschärfung kommt später, wenn alle Zeilen gefüllt sind.
Wie migriere ich große Tabellen sicher?
In Blöcken statt in einem Statement. Ein Update über Millionen Zeilen sperrt die Tabelle und legt die Anwendung lahm. Sinnvoll sind Pakete von einigen tausend Zeilen, ein festgehaltener Fortschritt und die Möglichkeit, jederzeit anzuhalten und fortzusetzen. Nach jedem Block folgt ein Abgleich.
Was passiert, wenn Contract nie stattfindet?
Dann ist das Ergebnis schlechter als der Ausgangszustand. Es gibt zwei Wege zum selben Ziel, beide müssen gepflegt werden, und neue Entwickler wissen nicht, welcher gilt. Deshalb gehört der Aufräumschritt von Anfang an als eigenes Ticket in die Planung, mit Termin.
Wie hängt Parallel Change mit Feature Flags zusammen?
In der Migrate Phase steuert ein Flag, welche Variante genutzt wird. Damit lässt sich die Umstellung ohne neues Deployment aktivieren und im Fehlerfall sofort zurückdrehen. Nach der Contract Phase wird das Flag wieder entfernt, sonst sammeln sich tote Schalter im Code an.
Kann Rector bei der Migrate Phase helfen?
Ja, besonders bei vielen gleichartigen Aufrufstellen im eigenen Code. Eine eigene Regel stellt hunderte Stellen einheitlich um, statt sie von Hand zu bearbeiten. Bei fachlich unterschiedlichen Aufrufen bleibt Handarbeit mit Review nötig, dann hilft Rector nur beim Auffinden.
Gilt das Muster auch für REST APIs?
Ja, und dort besonders. Das neue Feld kommt zusätzlich in die Antwort, das alte bleibt zunächst erhalten. Clients wechseln in ihrem Tempo, danach wird das alte Feld entfernt. Das ist oft angenehmer als eine neue API Version, weil nur ein Endpunkt gepflegt werden muss.
Wie hilft Never Code Alone bei solchen Umstellungen?
Wir planen die Phasen gemeinsam, schreiben die Migrationen und richten die Prüfungen ein, die bestätigen, dass Contract wirklich sicher ist. Am Anfang steht ein kostenloses Kennenlernen, anschließend schätzen wir den Aufwand. Abgerechnet wird transparent nach Minuten, ohne Festpreis und ohne Mindestlaufzeit.