Kaum eine Woche vergeht, in der nicht ein weiteres Unternehmen stolz seine Pattern Library bzw. zunehmend sein Design System ins Web stellt. Was weit weniger öffentlich diskutiert wird, ist wie es sechs Monate später um diese Projekte steht. Erfahrungsgemäß sind Pattern Libraries (vergleichbar mit Balkongärten) nämlich von zwei Formen der Vernachlässigung bedroht: Dem Verdorren und dem Überwuchern.
Verdorren ist dann eine Gefahr, wenn die Patterns, trotz ihrer Verknüpfung mit lebendigem CSS, nicht wirklich angenommen werden, weil sie technisch oder funktional an den Bedürfnissen im Unternehmen vorbei gehen oder nicht genügend evangelisiert wurden.
Umgekehrt kann eine Pattern Library aber auch an ihrem eigenen Erfolg zugrunde gehen und zuwuchern, weil zu viele neue Patterns mit überlappender Funktionalität eingepflegt werden, bis praktisch das gesamte UI in der Library liegt und niemand mehr den Überblick hat.
Während sich Pattern Libraries für kleine Teams relativ leicht aufsetzen lassen, erfordert die Integration einer unternehmensweiten Pattern Library mehr architekturelle Planung. Dabei gibt es einige zentrale Entscheidungen, die auf die technische Umsetzung und die notwendigen organisatorischen Prozesse wirken. Diese Optionen sollen hier mit Vor- und Nachteilen vorgestellt werden, damit nach sechs Monaten weder Verdorren noch Überwuchern zum Problem werden.
Bei einer Pattern Library für mehrere Teams stellt sich dabei zuallererst die Frage, wie stark die Pflege der Patterns zentralisiert ist und wer eigentlich den Hut aufhat, wenn es um Patterns geht.
Pattern Libraries managen
Zentral gepflegte Pattern Libraries
Beim zentralistischen Ansatz übernimmt ein eigenes Pattern-Team Wartung und Pflege der Library für den Rest des Unternehmens. Die Zuständigkeiten sind somit klar geregelt, weil das Pattern-Team optimalerweise eine eigene Product Owner_in/Manager_in hat, die die Entwicklungs-Roadmap im Blick behält. Anders als die anderen Teams kann diese gut überblicken, ob eine Anforderung ein Pattern zu sehr überdehnt und damit zu schwer wartbarem Code und einer unübersichtlichen Library führt.
Ein zusätzliches Team verursacht allerdings zusätzliche Kosten: Damit die Pattern Library kontrolliert wächst, müssen die Produkt- und Designsicht wie auch die technische Sicht abgedeckt werden. Es braucht also eine Produktmanager_in, eine Software Architekt_in, eine Designer_in und eine Entwickler_in, die sich zumindest in Teilzeit mit dem Thema befassen. Die Pflege komplett zu zentralisieren macht deshalb erst Sinn, wenn die Pattern Library von vielen Teams genutzt wird, die kontinuierlich neue Anforderungen produzieren.
Ist die Auslastung des Pattern-Teams gegeben, muss sichergestellt werden, dass es nicht zum Flaschenhals für die anfordernden Teams wird. Hier liegt die große Gefahr beim zentralistischen Ansatz, weil Anforderungen gerne in Schüben kommen und das zentrale Pattern-Team dann von anderen Teams schnell eher als Hindernis denn als Erleichterung wahrgenommen wird. Das wiederum sorgt dafür, dass neue Features eher lokal in den Teams als in der Pattern Library entwickelt werden.
Etwas lindern lässt sich diese Gefahr, wenn man das Pattern-Team aus dem Scrum-Sprint-Takt nimmt und flexibel via Kanban managed. Geschützte und vorab geplante Scrum-Zyklen vertragen sich schlecht mit agilen Anforderungen zu Sprintbeginn durch die anderen Teams.
Verteilt gepflegte Pattern Libraries
Statt die Pattern Library zentralisiert zu pflegen, können die verschiedenen Teams selbst Zugriff auf das Repository der Patterns erhalten. Dadurch können Verzögerungen durch ein überlastetes Pattern-Team vermieden werden und die beteiligten Teams sich stärker mit der Pattern Library identifizieren.
Hier besteht allerdings die Gefahr, dass die Zahl der Patterns rapide ansteigt und die Pattern Library groß und unübersichtlich wird. Dies schadet sowohl der Wartbarkeit, der Performance wie auch der User Experience.
Um verteilte Pattern Libraries zu pflegen, braucht es deshalb trotzdem zentralisierte Verantwortlichkeiten. Es muss klar sein, wer die Produktvision, die technische und die gestalterische Perspektive der Pattern Library verantwortet. Dazu sind mindestens eine Produktmanager_in (PM) und eine Architekt_in erforderlich, die im Optimalfall von einer Designer_in unterstützt werden. Natürlich können diese Rollen auch von Mitgliedern bestehender Teams gefüllt werden.
Die Verantwortung und damit Entscheidung für die Produktentwicklung der Pattern Library muss letztendlich zentral bei einer PM liegen. Diese Person hat auch die Verantwortung, fachliche Anforderungen aus dem Unternehmen für neue Patterns zusammenzutragen. Das ist erfahrungsgemäß ein kommunikationsaufwändiger Prozess, die Pattern-PM muss also genügend Ressourcen für die schnelle Bearbeitung zur Verfügung haben.
Neue Patterns müssen vorab mit der Pattern-PM abgeklärt werden, damit es zu keinen Überschneidungen kommt und der Umfang der Pattern Library handhabbar bleibt. Commits in das Pattern Repository müssen technischen Standards genügen und werden von der Architekt_in reviewed.
Dieses zentralisierte Organisationselement in der verteilten Pflege birgt natürlich wieder die Gefahr des Flaschenhalses. Es muss deshalb sichergestellt werden, dass PM und Architekt_in genügend Ressourcen und definierte Vertretungen zur Verfügung haben, um dieser Aufgabe nachzukommen und wartende Pull-Requests oder PM-Absprachen keine Gefahr für Sprint-Abschlüsse werden.
Tipps für die Auswahl von Patterns
Unabhängig vom gewählten Modell sollten folgende Grundsätze beachtet werden, um die Pattern Library als Produkt weiterzuentwickeln:
- Kleine Patterns bevorzugen: Es ist wichtig, dass die Pattern Library eine breite Auswahl von atomaren UI-Elementen wie Slidern, Toggles, Buttons usw. enthält, aus denen größere Komponenten zusammengestellt werden können. Solche Elemente sollten frühzeitig inkludiert und aus Team-Designs extrahiert werden. Größere Komponenten dagegen haben weniger Potenzial wiederholt eingesetzt zu werden, und sollten deshalb genauer auf ihren Nutzen geprüft werden.
- Ein Pattern ist per Definition – die stammt in diesem Fall vom Kollegen Wolf Brüning – ein sich wiederholendes Element. Damit die Library schlank bleibt, sollte ein Pattern wenigstens von zwei Teams genutzt werden. Patterns, die sich nur teamintern wiederholen, müssen nicht die gemeinsame Code-Basis vergrößern.
- Balance zwischen Flexibilität und Konsistenz halten. Je größer die Pattern Library wird und ihr Nutzerkreis wächst, umso mehr neue Anforderungen an Patterns kommen hinzu, was die Anzahl der Varianten erhöht. Die PM muss also auf Konsistenz und Wiederverwendung der existierenden Patterns pochen. Gleichzeitig muss ein gewisses Maß an Flexibilität gewahrt bleiben, um auf sich ändernde Voraussetzungen eingehen zu können. Hier findet sich das Open/Closed Prinzip wieder, dass von Software-Modulen fordert, dass sie für Erweiterung offen, aber für Veränderung geschlossen sind. Leider lässt sich dieses Prinzip in reinem CSS nicht technisch erzwingen, es braucht also die Durchsetzungskraft der PM.
Code teilen
Patterns müssen nicht nur inhaltlich und gestalterisch, sondern auch technisch koordiniert werden – dafür hilft es, sich frühzeitig auf gemeinsame Code-Styles für Patterns zu einigen. Zum Glück gibt es da inzwischen einige bewährte, auf die man aufbauen kann, etwa Harry Roberts CSS Richtlinien für CSS/SASS und die Javascript-Regeln von Airbnb. Letztere lassen sich auch mit eslint leicht automatisiert überprüfen, was erfahrungsgemäß zu wesentlich besserer Akzeptanz führt. Für CSS/SASS leistet das stylelint in ähnlicher Weise.
Unabhängig davon, ob eine Pattern Library zentralisiert oder verteilt gepflegt wird, besteht ab einer gewissen Unternehmensgröße eine gemeinsame technische Abhängigkeit von mehreren Teams. Das bringt zwar die bereits beschriebenen Vorteile in Sachen Konsistenz und Reduktion von Redundanzen, unabhängige agile Teams müssen sich aber die Frage stellen, mit welcher Version der Pattern Library sie arbeiten und wie Updates erfolgreich verteilt werden könne.
Lose Kopplung von Teams
Die erste Möglichkeit ist die Pattern Library zu behandeln wie jede andere externe Abhängigkeit auch: Die Pattern Library wird versioniert und jedes Team kann für sich entscheiden, mit welcher Version es arbeiten will. Nicht rückwärtskompatible Änderungen lösen daher nicht sofort Handlungsbedarf bei den Teams aus, da sie selbst entscheiden, wann sie den Versionssprung vollziehen.
Diese lose Kopplung stört also die Autonomie der Teams nicht und bietet organisatorisch klare Vorteile. Ein Team, das neue Features in die Pattern Library integrieren will, ist durch die lineare Versionierung allerdings gezwungen, erst auf die aktuellste Version zu aktualisieren, bevor das neue Feature hinzugefügt werden kann.
Die PM der Pattern Library muss in diesem Modell nur mit jeder Version das Change Log und Hinweise zur Rückwärtskompatibilität der Änderungen an alle Teams kommunizieren, organisatorische Abhängigkeiten entstehen durch diese Updates nicht.
Um die Informationen zur Rückwärtskompatibilität direkt in der Versionsnummer zu kodieren bietet es sich an Semantic Versioning einzusetzen. Das Schema folgt der Regel Major.Minor.Patch und verlangt, dass alle Updates auf Patch- oder Minor-Ebene komplett rückwärtskompatibel sind. Jedes Team kann sich also darauf verlassen, dass ein Update von beispielsweise 1.4.1 auf 1.7.4 keine Probleme macht.
Dieses Versionierungsschema macht auch deshalb Sinn, weil es sich gut in NPM integriert. NPM ist der Paketmanager zu Node.JS, mit dem die Pattern Library als versioniertes Paket zentral für die Teams bereitgestellt werden kann.
Liegt die Pattern Library als semantisch versioniertes NPM-Paket auf dem Server, muss jedes Team nur noch in seiner package.json definieren, mit welcher Major-Version es arbeiten mag, Minor/Patch-Updates werden dann automatisch mit jedem npm update eingespielt, während Major-Updates eine manuelle Anpassung der Datei voraussetzt. Auch wer seine Pattern Library nicht öffentlich machen will, kann dank Nexus oder Sinopia auf die NPM-Infrastruktur zurückgreifen.
Enge Kopplung von Teams
Die lose Kopplung von Teams hat klare organisatorische Vorteile, sie hat allerdings einen entscheidenden Nachteil: Wenn mehrere Teams an einer gemeinsamen Website arbeiten und mit ihren Patterns und Assets völlig entkoppelt sind, müssen User der Website die gleichen Patterns mehrfach herunterladen. Das klingt im ersten Moment nicht nach viel, aber eine Pattern Library enthält unter Umständen nicht nur CSS, sondern auch (Icon-)Fonts, Logos und geteilte Skripte. So entsteht ein ernsthaftes Performance-Problem, da die Redundanzreduktion nicht an das Frontend weitergegeben wird. Falls sich Patterns optisch verändern, sind so die verschieden Teams nicht immer auf einem visuellen Stand – die Flexibilität wird also auf Kosten der Konsistenz gewonnen. Dieses Setup birgt grundsätzlich die Gefahr von persistierenden schiefen Ständen: setzt ein Team noch eine alte Major-Release ein, haben diese Teile der Seite dann auch eine veraltete Optik.
Für Teams, die an einer gemeinsamen Website arbeiten, macht es deshalb Sinn, auch die gleiche Version der Pattern Library einzusetzen und auszuliefern.
Der Zwang, im Produktionsbetrieb mit der gleichen Version der Pattern Library zu arbeiten, koppelt die Teams organisatorisch deutlich enger aneinander. Minor-Versionen und Patches können weiterhin ohne größeren Aufwand eingespielt werden, sobald aber mit einem Major-Versionssprung die Rückwärtskompatibilität gebrochen wird, müssen alle eng gekoppelten Teams im gleichen Release ihre Templates aktualisieren.
Um diese Abhängigkeit organisatorisch zu handhaben, hat sich folgendes Muster bewährt:
- Team 1 plant eine Änderung in einem Pattern, das nicht rückwärtskompatibel ist. Es dupliziert deshalb das Pattern und setzt die Änderung mit der CSS-Modifier-Klasse .pattern.v2 um. Das bedeutet, das alte Pattern kann weiterhin eingesetzt werden, der Zusatz .v2 lädt die neuen Styles;
- Team 1 kontaktiert alle anderen Teams, damit sie ihre Templates auf .pattern.v2 updaten;
- Jedes Team gibt eine Rückmeldung, sobald das Impediment aufgelöst wurde;
- Wenn alle Teams das neue Pattern einsetzen, löscht Team 1 das ursprüngliche Pattern;
- Team 1 informiert alle Teams, dass sie den Zusatz .v2 wieder entfernen können.
Dieses Muster stellt sicher, dass das Frontend zu jedem Zeitpunkt voll funktionsfähig bleibt und eignet sich deshalb für Continuous Integration. Der Kommunikationsaufwand ist natürlich deutlich höher als bei der losen Kopplung. Um den Überblick zu teamübergreifenden Impediments und deren Zustand zu behalten, kann ein gemeinsames KANBAN-Board eingesetzt werden.
Eine weitere Herausforderung bei der engen Kopplung ist die Versionsverwaltung. Während bei der losen Kopplung jedes Team selbst entscheidet, mit welcher Version der Pattern Library es arbeitet, muss in diesem Fall der Pattern Library-Build selbst wissen, welche Version er ausliefern soll. Diese Version kann je nach Umgebung (Development, Staging, Produktion, etc.) eine andere sein, diese Information muss also dem Build zugänglich gemacht werden.
Enge und lose Koppelung schließen sich natürlich nicht aus, in einem Unternehmen kann es also Teams geben die eng gekoppelt sind und andere, die nicht jeden Versionssprung mitnehmen.
Säen und Ernten
Wenn Pattern Libraries wachsen, fängt die eigentliche Arbeit erst an, aber es ist auch der Punkt an dem sie ihre Stärken zeigen: Wirklich konsistent über eine Vielzahl von Teams zu gestalten und Code-Duplizierungen zu vermeiden, ist ohne gemeinsame Patterns fast nicht zu schaffen. Wie bei allen digitalen Plänen lohnt es sich, außerdem schrittweise vorzugehen: Eine Pattern Library braucht nicht sofort ihr dediziertes Team und eine komplexe Build-Pipeline, um gemeinsame Assets auszuliefern. Am Anfang braucht sie vor allem Akzeptanz, es ist also wichtig, möglichst einfach und überzeugend zu starten und dann schrittweise auszubauen, wenn sich Engpässe andeuten.
Danke für diese gelungene Darstellung und zahlreichen Tipps. Ein Ratgeberbeitrag wie er sein sollte :).
Danke dir! Schön, dass der Artikel weitergeholfen hat.