Preference vs. Plugin: Kompatibilitäts- und Update-Risiken abwägen
Preference vs. Plugin: Kompatibilitäts- und Update-Risiken abwägen
~7 Min. Lesezeit Zuletzt aktualisiert am 9. August 2026
Kapitel 41 hat eine echte, saubere Preference geschrieben - und trotzdem einen gewissen Preis dafür bezahlt. Dieses Kapitel macht den Preis explizit: zwei konkrete Risikoarten, die eine Preference eingeht und ein Plugin nicht, und wie man beide in der Praxis kleinhält.
Risiko 1: mehrere Preferences auf dasselbe Ziel
Registriert irgendein drittes Modul ebenfalls eine Preference für ErpSync\CorporateRewards\Api\MultiplierResolverInterface, entscheidet allein die Modul-Ladereihenfolge (sequence in module.xml, dann alphabetisch), welche der beiden Preferences am Ende tatsächlich instanziiert wird. Es gibt keine Fehlermeldung, keinen Compile-Warnhinweis, keinen Log-Eintrag - der Code läuft einfach weiter, nur eben mit der falschen Implementierung. Das steht in scharfem Kontrast zu Plugins: mehrere Module können denselben Interceptor-Punkt gemeinsam nutzen, Magento führt alle registrierten Plugins in sortOrder-Reihenfolge aus (Kapitel 43), statt nur eines davon gewinnen zu lassen.
In der Praxis lässt sich ein solcher Konflikt am zuverlässigsten aufspüren, indem alle <preference>-Einträge für ein bestimmtes Interface projektweit gesucht werden:
grep -rl 'for="ErpSync\\\\CorporateRewards\\\\Api\\\\MultiplierResolverInterface"' app/code vendorRisiko 2: Kopplung an die gesamte Klassenoberfläche
Ein Plugin koppelt ausschließlich an eine Methodensignatur - ändert der Hersteller sie in einem Update inkompatibel, meldet setup:di:compile den Fehler sofort und laut. Eine Preference koppelt dagegen an die gesamte Klasse: bekommt MultiplierResolverInterface in einem künftigen Erweiterungs-Update eine zusätzliche Methode, muss CompanyMultiplierPreference (Kapitel 41) sie ebenfalls implementieren, sonst bricht die Preference mit einem "Class must implement interface"-Fehler komplett weg - kein einzelner kaputter Aufruf, sondern der komplette Service ist nicht mehr instanziierbar.
Noch tückischer: ändert der Hersteller nur das interne Verhalten von resolveForCompany() (nicht die Signatur), fällt das gar nicht auf - CompanyMultiplierPreference nutzt weiterhin die alte, per Komposition eingebundene Logik, solange MultiplierResolver selbst kompatibel bleibt. Das ist in diesem konkreten Fall harmlos (Komposition schirmt genau davor ab), wäre aber bei einer Preference, die den Original-Code komplett neu implementiert statt zu komponieren, ein stiller Drift-Fehler.
Praktische Abwägung
- Wo immer möglich gegen ein Interface preferencen, nicht gegen eine konkrete Klasse - reduziert die Kopplung auf den vertraglich zugesicherten Teil.
- Komposition statt Reimplementierung (Kapitel 41): je mehr Original-Logik wiederverwendet statt kopiert wird, desto kleiner die Fläche, die bei einem Update auseinanderdriften kann.
- Jede Preference im Code klar als bewusste Ausnahme kommentieren (welches strukturelle Hindernis, warum kein Plugin) - der nächste Entwickler soll sie nicht versehentlich als Vorbild für den nächsten, eigentlich plugin-fähigen Fall nehmen.
- Nach jedem Drittanbieter-Modul-Update gezielt prüfen, ob die preferencte Interface-Signatur noch identisch ist -
setup:di:compiledeckt fehlende Methoden auf, aber nicht reine Verhaltensänderungen.
Tipp: CLAUDE.md verlangt "Plugins statt Preferences" nicht aus Dogmatismus, sondern weil genau diese beiden Risiken bei Plugins strukturell nicht existieren. Block 5 nutzt in Kapitel 41 die Preference-Ausnahme exakt einmal, exakt begründet, exakt dokumentiert - das ist der Maßstab, nicht die Häufigkeit.
Achtung: Preference und Plugin auf dasselbe Interface gleichzeitig einzusetzen, funktioniert technisch, verwirrt aber leicht: die Preference entscheidet beim Aufbau des Objektgraphen, welche Klasse überhaupt instanziiert wird - danach erst wickelt sich der Plugin-Interceptor um das Ergebnis dieser Entscheidung. Ein Plugin auf MultiplierResolverInterface würde also automatisch auf CompanyMultiplierPreference wirken, nicht mehr auf die ursprüngliche MultiplierResolver-Klasse.
Damit sind die Risiken einer Preference klar benannt. Kapitel 43 wendet sich wieder Plugins zu - genauer: der Frage, wie mehrere Plugins auf demselben Ziel und aus unterschiedlichen Modulen sauber zusammenspielen.