verstehen, bevor das nächste Upgrade bricht
Ein Magento-Upgrade, das plötzlich eigene Module zerlegt, liegt fast immer an derselben Ursache: irgendwo im Code wurde eine Klasse erweitert oder überschrieben, die Adobe nie als stabile Schnittstelle zugesagt hat. Wer versteht, was das @api-Tag bedeutet und warum Plugins die sichere Erweiterungsmethode sind, baut Module, die Magento-Updates ohne böse Überraschungen überstehen.
Inhaltsverzeichnis
- 1. Was Magentos Backward-Compatibility-Policy regelt
- 2. Das @api-Tag: was als stabile Schnittstelle zählt
- 3. Warum Plugins die BC-sichere Erweiterung sind
- 4. Deprecation in Magento-Core richtig lesen
- 5. Was die BC-Policy explizit nicht schützt
- 6. Auswirkungen auf eigene Module: sich selbst absichern
- 7. BC-Breaks bei Minor-Updates rechtzeitig erkennen
- 8. Praxis-Checkliste vor jedem Magento-Upgrade
- 9. BC-konforme vs. riskante Erweiterungspraxis
- 10. Zusammenfassung
- 11. FAQ
1. Was Magentos Backward-Compatibility-Policy regelt
Adobes Backward Compatibility Policy für Magento 2 legt fest, welche Teile des Frameworks als stabile, langfristig unveränderte Schnittstelle gelten und welche jederzeit ohne Vorwarnung geändert werden dürfen. Das ist keine akademische Feinheit, sondern die praktische Grundlage dafür, wie man eigene Module und Anpassungen so baut, dass ein Magento-Minor- oder Patch-Update sie nicht zerstört. Ohne dieses Verständnis wirkt jedes Upgrade wie ein Glücksspiel.
Der Kern der Policy ist simpel formuliert: Klassen, Interfaces und Methoden, die als @api markiert sind, gelten als öffentliche Schnittstelle und werden innerhalb einer MAJOR-Version nicht inkompatibel geändert. Alles andere, egal wie stabil es über Jahre wirkte, kann sich mit jedem Patch-Release ändern. Diese Backward Compatibility Garantie gilt ausschließlich für als API gekennzeichneten Code, nicht für die Codebasis als Ganzes.
Adobe veröffentlicht die Details dieser Policy öffentlich als Teil der Magento-Entwicklerdokumentation, inklusive einer Liste der Kriterien, nach denen eine Klasse als API klassifiziert wird. Wer diese Kriterien einmal verinnerlicht hat, kann sie sofort auf jede Magento-Klasse anwenden, ohne bei jeder einzelnen Entscheidung erneut nachschlagen zu müssen.
Für Agenturen, die viele Magento-Shops über Jahre pflegen, ist die Kenntnis dieser Regeln der Unterschied zwischen einem planbaren Upgrade-Prozess und wiederkehrenden Feuerwehreinsätzen nach jedem Patch-Release. Wer weiß, worauf sich Magento wirklich committet, kann eigene Erweiterungen gezielt gegen genau diese Garantien bauen, statt sich auf zufällig stabil wirkenden internen Code zu verlassen.
Diese Policy ist außerdem kein rein technisches Detail, sondern hat direkte wirtschaftliche Konsequenzen. Jede Stunde, die in ein Upgrade investiert werden muss, weil eine ungeschützte interne Klasse sich geändert hat, ist eine Stunde, die im Projektbudget nicht für neue Funktionen zur Verfügung steht. Teams, die Backward Compatibility von Anfang an mitdenken, verschieben diesen Aufwand von reaktiver Fehlersuche nach jedem Update hin zu einer einmaligen, bewussten Architekturentscheidung.
2. Das @api-Tag: was als stabile Schnittstelle zählt
Das @api-Tag im PHPDoc-Block einer Klasse oder eines Interfaces ist das zentrale Signal von Magentos Backward Compatibility Policy. Ist eine Klasse mit @api annotiert, verspricht Adobe, dass ihre öffentliche Signatur innerhalb derselben MAJOR-Version stabil bleibt. Service Contracts wie \Magento\Catalog\Api\ProductRepositoryInterface sind das klassische Beispiel: sie sind durchgängig mit @api markiert und genau dafür gedacht, von eigenem Code verwendet zu werden.
Fehlt das @api-Tag, gilt eine Klasse implizit als interne Implementierungsdetails, selbst wenn sie öffentlich (public) und seit Jahren unverändert ist. Genau das überrascht viele Entwickler: Sichtbarkeit im PHP-Sinne und Stabilität im Sinne der Backward Compatibility Policy sind zwei komplett unabhängige Eigenschaften. Eine public-Methode ohne @api kann sich in jedem Patch-Release ändern, ohne dass das als Breaking Change gilt.
<?php
declare(strict_types=1);
namespace Magento\Catalog\Api;
/**
* Product repository interface.
*
* @api
*/
interface ProductRepositoryInterface
{
public function get($sku, $editMode = false, $storeId = null, $forceReload = false);
public function save(\Magento\Catalog\Api\Data\ProductInterface $product, $saveOptions = false);
public function delete(\Magento\Catalog\Api\Data\ProductInterface $product);
}
// Classes WITHOUT @api, even if public, are considered internal
// implementation details and may change in any patch release.
Praktische Konsequenz: bevor eine eigene Erweiterung eine Magento-Klasse referenziert, lohnt der Blick in den Docblock. Steht dort @api, ist die Referenz sicher im Sinne der Backward Compatibility Policy. Fehlt das Tag, sollte die Abhängigkeit vermieden oder zumindest bewusst als Risiko dokumentiert werden, damit ein späteres Upgrade nicht überrascht.
Das @api-Tag lässt sich auch automatisiert auswerten. Ein einfaches Skript, das die Docblocks aller in einem eigenen Modul referenzierten Magento-Klassen einliest und auf das Vorhandensein von @api prüft, macht die Risikoeinschätzung reproduzierbar, statt sie von Fall zu Fall manuell im Code-Review zu wiederholen. Größere Agenturen betten diesen Check häufig direkt in die eigene CI-Pipeline ein und lassen ihn als eigenständigen Report neben PHPStan und den statischen Tests laufen.
3. Warum Plugins die BC-sichere Erweiterung sind
Ein Plugin (Interceptor) greift über Methodennamen in den Ablauf einer als @api markierten Methode ein, ohne deren interne Implementierung zu kennen oder zu berühren. Das macht Plugins zur bevorzugten Erweiterungsmethode unter Magentos Backward Compatibility Policy: solange die öffentliche Methodensignatur stabil bleibt, funktioniert das Plugin unabhängig davon, wie sich die interne Umsetzung der Methode über Versionen hinweg verändert.
Dieser Mechanismus funktioniert, weil Magentos Object Manager zur Laufzeit einen generierten Interceptor zwischen Aufrufer und Zielklasse schaltet. Der Interceptor kennt nur die öffentliche Signatur der Methode, niemals ihren Rumpf. Genau diese Indirektion ist der technische Grund, warum Plugins so robust gegenüber internen Refactorings sind: Adobe kann die komplette interne Logik einer Methode austauschen, solange Parameter und Rückgabetyp gleich bleiben, ohne dass ein einziges Plugin angepasst werden muss.
Eine Preference (Klassenüberschreibung via preference in di.xml) oder direkte Vererbung einer Core-Klasse verhält sich fundamental anders. Sie bindet sich an die komplette interne Struktur der Elternklasse, inklusive privater und protected Methoden, die niemals von der Backward Compatibility Policy erfasst sind. Ändert Adobe eine interne Methode oder Property in einem Patch-Release, bricht die eigene Preference, ohne dass Magento das als Regelverstoß werten würde.
<!-- app/code/Mironsoft/LoyaltyPoints/etc/di.xml -->
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<!-- SAFE: plugin only depends on the stable, @api-marked public interface -->
<type name="Magento\Catalog\Api\ProductRepositoryInterface">
<plugin name="Mironsoft_LoyaltyPoints::afterSave" type="Mironsoft\LoyaltyPoints\Plugin\ProductRepositoryPlugin"/>
</type>
</config>
Die Faustregel ist deshalb eindeutig: Plugins auf @api-Interfaces sind die sichere Wahl, Preferences auf Klassen ohne @api sind ein bewusst eingegangenes Risiko, und direkte Vererbung von Core-Klassen ohne @api ist die riskanteste Praxis überhaupt, weil sie sich an nicht garantierte interne Details bindet. Diese Priorisierung ist keine Stilfrage, sondern folgt direkt aus dem, was Magentos Backward Compatibility Policy tatsächlich zusichert.
4. Deprecation in Magento-Core richtig lesen
Bevor Adobe eine als @api markierte Klasse oder Methode tatsächlich entfernt, wird sie zunächst mit @deprecated markiert, oft ergänzt um einen @see-Verweis auf die empfohlene Alternative. Diese Deprecation-Phase ist Teil der Backward Compatibility Policy: eine als deprecated markierte, aber noch als @api geltende Methode bleibt innerhalb der aktuellen MAJOR-Version funktionsfähig, verschwindet aber garantiert in der nächsten MAJOR-Version.
Der entscheidende Fehler vieler Teams ist, @deprecated-Warnungen zu ignorieren, solange der Code noch läuft. Genau das rächt sich beim nächsten MAJOR-Upgrade, wenn plötzlich mehrere als deprecated markierte Abhängigkeiten gleichzeitig entfernt wurden und ein einzelnes Upgrade zu einem großen Refactoring-Projekt wird, statt schrittweise über mehrere Minor-Releases hinweg bearbeitet worden zu sein.
PHPStorm und andere IDEs zeigen @deprecated-Markierungen standardmäßig als durchgestrichenen Text an, was die Sichtbarkeit im Alltag deutlich erhöht, aber nur hilft, wenn Entwickler diese optische Warnung auch als Handlungsaufforderung verstehen und nicht als kosmetisches Detail ignorieren. Ein kurzer Hinweis im Team-Onboarding, dass durchgestrichener Code aktiv Migrationsbedarf signalisiert, verhindert viele spätere Überraschungen.
<?php
declare(strict_types=1);
namespace Magento\Framework\App\Config;
/**
* @deprecated 101.0.0 Use ScopeConfigInterface::getValue() with explicit scope instead.
* @see \Magento\Framework\App\Config\ScopeConfigInterface::getValue()
* @api
*/
public function getConfigDataValue($path, $default = null)
{
// Still functional in the current major version, but scheduled
// for removal. Migrate proactively instead of waiting for the break.
}
Ein regelmäßiger Grep nach @deprecated in den genutzten Vendor-Klassen, gekoppelt an einen fest eingeplanten Migrationszeitraum, verhindert, dass sich technische Schulden unbemerkt anhäufen. Gute Praxis ist, jede gefundene Deprecation als Ticket im Backlog zu erfassen, statt sie erst beim nächsten erzwungenen MAJOR-Upgrade zu entdecken.
5. Was die BC-Policy explizit nicht schützt
Ein häufiges Missverständnis ist, dass Magentos Backward Compatibility Policy die gesamte Codebasis abdeckt. Tatsächlich sind private und protected Methoden, interne Helper-Klassen, Klassen unter Namespaces wie *\Model\ResourceModel\* ohne @api, sowie sämtliche Implementierungsdetails hinter einem Service Contract explizit ausgenommen. Diese Bereiche können sich in jedem Patch-Release ändern, auch wenn sie über Jahre stabil erschienen.
Besonders tückisch sind Layout-XML-Handles, Block-Klassen ohne @api und Template-Dateien selbst: sie unterliegen keiner formalen Backward Compatibility Garantie, obwohl viele Themes und Module massiv auf sie zugreifen. Ein Theme, das ein Core-Template per copy-over kopiert, bindet sich an dessen exakte Struktur zum Zeitpunkt der Kopie und erhält keinerlei Update-Schutz, wenn Adobe das Original-Template später ändert.
Auch Datenbank-Tabellen und ihre Spaltenstruktur zählen grundsätzlich nicht zur geschützten API, selbst wenn sie über db_schema.xml deklarativ verwaltet werden. Direkte SQL-Zugriffe auf Core-Tabellen ohne den Umweg über ein Repository oder eine Collection sind deshalb eine der am häufigsten unterschätzten Quellen für Upgrade-Brüche, weil Adobe Tabellenstrukturen im Rahmen von Performance-Optimierungen oder Datenmodell-Änderungen ohne gesonderte Ankündigung anpassen kann.
Auch JavaScript-Module und Knockout-Templates im Frontend folgen keiner formalen Backward Compatibility Zusicherung, obwohl viele Hyvä- und Luma-Erweiterungen direkt auf sie zugreifen. Wer ein RequireJS-Modul per Mixin erweitert, sollte deshalb dieselbe Vorsicht walten lassen wie bei PHP-Preferences: je enger die Kopplung an interne Implementierungsdetails, desto größer das Risiko beim nächsten Frontend-Update.
6. Auswirkungen auf eigene Module: sich selbst absichern
Die praktische Konsequenz für eigene Module ist eine bewusste Abhängigkeitsstrategie: jede Referenz auf Magento-Core-Code sollte danach bewertet werden, ob sie ein @api-Ziel trifft. Für @api-Ziele ist ein Plugin oder eine direkte Nutzung des Interfaces via Dependency Injection sicher. Für Nicht-@api-Ziele sollte entweder eine Alternative über den Service Contract gesucht werden, oder die Abhängigkeit wird bewusst mit einem Kommentar dokumentiert, der auf das Risiko hinweist.
Diese Strategie gilt genauso für die eigene Modularchitektur: Module, die von mehreren Consumern genutzt werden, sollten selbst konsequent zwischen öffentlichen, mit @api markierten Interfaces und internen Implementierungsdetails unterscheiden. Wer diese Trennung im eigenen Code von Anfang an durchzieht, kann Magentos Backward Compatibility Denkweise eins zu eins auf die eigene Modulfamilie übertragen und profitiert selbst von derselben Update-Sicherheit, die man sich von Adobe wünscht.
Ein einfacher erster Schritt ist, im eigenen Modul konsequent @api auf alle Interfaces zu setzen, die als Erweiterungspunkt für andere Teams gedacht sind, und Klassen ohne diese Markierung klar als intern zu behandeln. Dieselbe Priorisierung, die man von Magento einfordert, sollte man der eigenen Codebasis nicht schuldig bleiben.
Ein wirksames Mittel ist ein automatisierter Check im eigenen CI, der nach extends-Beziehungen zu Nicht-@api-Klassen und nach preference-Einträgen in di.xml sucht, die auf Klassen ohne @api-Tag zeigen. So wird jede riskante Erweiterung sichtbar, bevor sie in ein Release wandert, statt erst beim nächsten Magento-Update als Fehler aufzufallen.
#!/usr/bin/env bash
set -euo pipefail
# Quick audit: list preference overrides in own modules and flag
# targets that are not marked @api in Magento core (manual review needed)
grep -r "preference for=" app/code/Mironsoft --include="di.xml" -A 0 | \
while read -r line; do
class=$(echo "$line" | grep -oP 'for="\K[^"]+')
echo "Reviewing preference target: $class"
done
# Search for direct inheritance from Magento core classes
grep -rn "extends \\\\Magento\\\\" app/code/Mironsoft --include="*.php"
# Search for plugins targeting classes without an @api tag nearby
grep -rln "<plugin " app/code/Mironsoft --include="di.xml" | while read -r file; do
echo "Plugin definitions in: $file"
done
# Flag any leftover copy-over templates that shadow a core template
find app/design/frontend -path "*/Magento_*/templates/*" -newer composer.lock
7. BC-Breaks bei Minor-Updates rechtzeitig erkennen
Auch innerhalb einer einzigen MAJOR-Version können Minor- und Patch-Releases von Magento Verhalten ändern, das formal nicht durch @api geschützt war, aber von vielen Modulen genutzt wurde. Adobes Release Notes und der öffentliche Changelog listen bekannte Verhaltensänderungen, werden aber häufig übersehen, weil Teams Magento-Updates rein als Sicherheitspatches behandeln, ohne die begleitende Dokumentation zu lesen.
Ein bewährtes Vorgehen ist, vor jedem Minor-Update gezielt nach Änderungen an den von eigenen Modulen genutzten Klassen zu suchen, etwa über einen Diff der relevanten Vendor-Dateien zwischen der aktuellen und der neuen Magento-Version. Das ist aufwendiger als ein blindes Update, verhindert aber genau die Klasse von Fehlern, die erst im Live-Betrieb sichtbar werden, weil sie keine offensichtliche Exception werfen, sondern nur das Verhalten leicht verändern.
Eine zusätzliche Absicherung bietet ein vollständiger MFTF-Regressionslauf gegen eine Staging-Kopie mit der neuen Magento-Version, bevor überhaupt ein Code-Review der Vendor-Diffs beginnt. Browser-basierte Tests decken genau jene subtilen Verhaltensänderungen auf, die sich in reinem Code-Diff kaum erkennen lassen, etwa eine leicht veränderte Reihenfolge von Observer-Aufrufen oder eine geänderte Standardsortierung in einer Collection, die kein Fehler im engeren Sinne ist, aber das Frontend sichtbar anders darstellt.
8. Praxis-Checkliste vor jedem Magento-Upgrade
Eine strukturierte Checkliste reduziert das Risiko eines Magento-Upgrades erheblich, gerade weil Backward Compatibility in der Praxis selten binär ist, sondern viele Graustufen zwischen "garantiert sicher" und "garantiert riskant" kennt. Vor jedem Upgrade lohnt sich eine gezielte Prüfung der eigenen Preferences, Plugins auf Nicht-@api-Ziele und kopierter Templates.
Ebenso wichtig ist ein Blick in den Magento-Changelog auf explizit als "Breaking Change" oder "Deprecation" markierte Einträge der Zielversion, kombiniert mit einem vollständigen MFTF- und Integrationstestlauf gegen eine Staging-Umgebung, bevor das Upgrade produktiv geht. Diese Kombination aus Code-Audit und automatisierter Testabdeckung fängt die meisten Backward Compatibility Probleme ab, bevor sie den Live-Shop erreichen.
Für die eigene Roadmap-Planung hilft es außerdem, eine feste Kadenz für BC-Reviews einzuplanen, etwa einmal pro Quartal, statt sie nur anlässlich eines bevorstehenden Magento-Upgrades ad hoc durchzuführen. So bleiben Preferences und Plugins auf dem aktuellen Stand der Magento-API-Dokumentation, statt über Jahre unbemerkt an veralteten Annahmen festzuhalten.
Zusätzlich lohnt sich ein Rollback-Plan, der vor dem Upgrade festgelegt wird, statt ihn im Fehlerfall unter Zeitdruck zu improvisieren. Ein vollständiges Datenbank-Backup, ein getaggter Deployment-Stand vor dem Update und eine klar definierte Entscheidungsgrenze, ab welchem Fehlerbild zurückgerollt statt weiter gepatcht wird, gehören ebenso zur Checkliste wie die reine Code-Analyse. Gerade bei MAJOR-Upgrades, bei denen mehrere Deprecations gleichzeitig entfernt werden, ist dieser Sicherheitsnetz-Charakter der Checkliste oft wichtiger als jede einzelne Codezeile.
9. BC-konforme vs. riskante Erweiterungspraxis
Die Wahl der Erweiterungsmethode hat direkte Konsequenzen für die Update-Sicherheit eines Moduls. Nicht jede Methode ist gleich riskant, und die Unterschiede sind erheblich genug, um sie bei jeder Architekturentscheidung bewusst gegeneinander abzuwägen.
| Erweiterungsmethode | BC-Sicherheit | Risiko bei Magento-Updates |
|---|---|---|
| Plugin auf @api-Interface | Hoch, formal zugesichert | Gering, Signatur bleibt stabil |
| Preference auf @api-Klasse | Mittel, Signatur stabil, Interna nicht | Mittel, bei internen Änderungen |
| Preference ohne @api | Niedrig, nicht zugesichert | Hoch, jeder Patch kann brechen |
| Direkte Vererbung ohne @api | Keine | Sehr hoch, komplette Interna gebunden |
| Core-Datei direkt gepatcht | Keine, verletzt jede Garantie | Maximal, Patch geht bei jedem Composer-Update verloren |
Die praktische Empfehlung folgt direkt aus dieser Tabelle: wo immer möglich, Plugins auf als @api markierte Interfaces bevorzugen. Ist eine Preference unvermeidbar, sollte sie ausschließlich auf @api-Klassen zielen und mit einem Kommentar dokumentiert werden, warum ein Plugin nicht ausreichte. Direkte Vererbung von Nicht-@api-Klassen sollte im Code-Review konsequent hinterfragt werden.
In der Praxis lohnt es sich, diese Tabelle als festen Bestandteil der Pull-Request-Checkliste zu etablieren. Ein Reviewer, der bei jeder neuen Preference oder jedem neuen Plugin kurz die Zeile in dieser Tabelle nachschlägt, verhindert zuverlässig, dass riskante Erweiterungspraxis unbemerkt in den Hauptbranch gelangt.
Mironsoft
Upgrade-sichere Magento-2-Architektur und BC-konforme Erweiterungspraxis
Das nächste Magento-Upgrade ohne Überraschungen?
Wir auditieren eure Preferences, Plugins und kopierten Templates auf Backward-Compatibility-Risiken und bauen eigene Module konsequent gegen Magentos @api-Garantien statt gegen zufällig stabilen internen Code.
BC-Audit
Preferences und Plugins auf Nicht-@api-Ziele identifizieren
Refactoring
Riskante Erweiterungen durch BC-sichere Plugins ersetzen
Upgrade-Begleitung
Systematische Checkliste und Testlauf vor jedem Magento-Update
10. Zusammenfassung
Magentos Backward Compatibility Policy ist keine vage Absichtserklärung, sondern ein präzises Regelwerk mit einem einzigen zentralen Signal: dem @api-Tag. Nur als API markierter Code ist innerhalb einer MAJOR-Version garantiert stabil, alles andere kann sich jederzeit ändern. Plugins auf @api-Interfaces sind deshalb die bevorzugte Erweiterungsmethode, während Preferences und direkte Vererbung von Nicht-@api-Klassen bewusste Risiken eingehen, die dokumentiert und regelmäßig überprüft werden sollten.
Wer diese Regeln systematisch anwendet, verwandelt Magento-Upgrades von einem riskanten Ereignis in einen planbaren Prozess. Ein regelmäßiger Blick auf @deprecated-Markierungen, ein automatisierter Check auf riskante Preferences und eine feste Checkliste vor jedem Upgrade sind der praktische Kern einer Architektur, die mit Magento mitwächst statt bei jedem Release neu zusammengeflickt zu werden.
Am Ende ist Magentos Backward Compatibility Policy weniger eine Einschränkung als ein Angebot: Adobe zeigt präzise, welcher Code langfristig verlässlich ist, und wer dieses Angebot konsequent nutzt, muss Upgrades nicht mehr fürchten, sondern kann sie als planbaren, wiederkehrenden Teil des Projektalltags behandeln.
Magentos BC-Policy: Das Wichtigste auf einen Blick
Das @api-Tag
Einziges verlässliches Signal für innerhalb einer MAJOR-Version stabilen Code.
Plugins bevorzugen
Plugins auf @api-Interfaces sind die sicherste Erweiterungsmethode gegen Upgrades.
Deprecation ernst nehmen
@deprecated-Markierungen frühzeitig migrieren, statt bis zum erzwungenen MAJOR-Upgrade zu warten.
Upgrade-Disziplin
Checkliste, Code-Audit und Testlauf vor jedem Update statt blindem Vertrauen.
Die folgenden Fragen fassen die häufigsten praktischen Unsicherheiten rund um Magentos Backward-Compatibility-Policy zusammen.