Beliebte Suchanfragen
|
//

Feature-Sliced Design und was wir für eine gute Frontend-Architektur brauchen

23.1.2025 | 9 Minuten Lesezeit

Feature-Sliced Design und was wir für eine gute Frontend-Architektur brauchen

Während zum Thema Softwarearchitektur im Backend schon viel publiziert wurde und es gut erprobte Best-Practices gibt, is dieses Thema für Frontend-Anwendungen weniger präsent und wird häufig eher vernachlässigt.

Angesichts der gestiegenen Komplexität von Frontend-Anwendungen durch erhöhte Anforderungen an UX und UI in den letzten Jahren, ist eine solide Anwendungsarchitektur unerlässlich, sofern die Weiterentwicklung auch die nächsten Jahre noch Spaß machen soll.

Die Methodik Feature-Sliced Design kann eine Lösung sein, um komplexe Frontend-Anwendungen mit einer sauberen Software Architektur zu strukturieren.

Was ist eine gute Software Architektur im Frontend?

Die Tage, an denen ein Frontend lediglich dazu da war, Daten zu formatieren und im Client anzuzeigen, sind lange vorbei. Ein modernes Frontend muss komplexe Statusänderungen, Benutzerinteraktionen und diverse Schnittstellen verarbeiten. Oft arbeiten mehrere Entwickelnde am selben Code und Änderungen müssen zeitnah umgesetzt werden können.

Mit einer “gewachsenen” Segmentierung der Anwendung in zweckgebundene Gruppen wie Services, Shared, UI, Api, o.ä. und ungeordneten Abhängigkeiten zueinander wird man den Anforderungen an eine saubere Architektur schnell nicht mehr gerecht. Man riskiert Wildwuchs, neue Mitarbeitende tun sich damit schwer, sich mit dem Quellcode vertraut zu machen und jede Änderung wird zu einem Risiko.

Für eine “saubere Anwendungsarchitektur” im Hinblick auf die Anwendungsstruktur sollten folgende Qualitätskriterien gelten:

  • Klarheit und Verständlichkeit: Softwarearchitektur sollte klar und leicht verständlich sein. Entwickelnde und Stakeholder sollten sie leicht verstehen und navigieren können.
  • Skalierbarkeit: Eine Anwendung sollte in der Lage sein, mit der Zeit zu wachsen und sich zu erweitern, um neue Anforderungen und Funktionen zu erfüllen.
  • Flexibilität: Anpassungen an neue Anforderungen sollten mit geringstmöglichem Aufwand umgesetzt werden können, ohne dass das gesamte System neu gestaltet werden muss.
  • Wartbarkeit: Eine Anwendung sollte so gestaltet sein, dass sie leicht gewartet und aktualisiert werden kann. Fehler können schnell lokalisiert und behoben werden.
  • Konsistenz: Die Struktur einer Anwendung sollte konsistent sein, d.h. sie sollte einheitliche Muster und Praktiken verwenden.

Oder wie es Douglas Crockford gesagt hat:

“Good architecture is necessary to give programs enough structure to be able to grow large without collapsing into a puddle of confusion.”

Um das zu erreichen, hilft uns ein Korsett aus Regeln und Leitplanken, die uns bei der Erweiterung einer Anwendung unterstützen.

Eine Antwort hierfür bietet die Methodik Feature-Sliced Design.

Wie funktioniert Feature-Sliced Design (FSD)

Im Grunde ist FSD nur eine Strukturvorgabe für Anwendungen mit einem Regelsatz, wie Elemente miteinander in Abhängigkeit stehen dürfen.

Dabei ist die Einteilung der Anwendung in 3 Ebenen ein zentraler Bestandteil: Layers, Slices und Segments.

Feature-Sliced Design Layers, slices and Segments

Die Unterteilung erfolgt in einer Hierarchie von links nach rechts. D.h. ein Layer ist in Slices unterteilt und ein Slice ist wiederum in Segments unterteilt.

App und Shared bilden dabei eine Ausnahme insofern, dass sie keine Slices, sondern nur Segments unter sich haben.

Eine Beispielhafte Ordnerstruktur in einer Anwendung könnte also so aussehen:

Feature-Sliced Design Folders and Slices

Während die Wahl der Slices die Geschäftslogik der Anwendung abbildet und in der Benennung keine Konvention vorgibt, gibt es bei der Auswahl der Layer und Segments gewisse Vorgaben.

Layers

Die in der Grafik genannten Layer App, Pages, Widgets, Features, Entities und Shared sind von FSD vorgegeben, müssen aber nicht alle verwendet werden.

Neben der Benennung gibt FSD eine weitere wichtige Regel vor: Jeder Layer darf nur von Layern unterhalb seiner Hierarchie wissen. D.h. Pages darf nur Widgets, Entities und Shared nutzen. Shared dagegen darf selbst keine Abhängigkeiten zu anderen Komponenten haben, auch nicht innerhalb des eigenen Layers.

Diese Vorgabe macht weiter Sinn, wenn man sich den Zweck der unterschiedlichen Layer anschaut:

App

Ist für die Laufzeitumgebung bzw. Bootstrapping der Anwendung zuständig. Konfigurationen, Style Definitionen und State Management auf globaler Ebene passen hierher. Darüber hinaus macht es Sinn, das Routing hier zu verorten. Typischerweise gibt es hier keine weitere Unterteilung in Slices, da sich hier keine Fachlogik befinden sollte.

Pages

Unterhalb Pages sollten komplette Ansichten, z.B. verknüpft durch Top-Level-Routing in dedizierten Slices angelegt werden.

Typischerweise sind die Slices in Segments unterteilt, da hier viele Seiten-spezifische Komponenten, Services und Konfigurationen organisiert werden müssen.

Im Prinzip alles, was nicht an anderer Stelle wiederverwendet wird, ist innerhalb eines Seiten-Slice und damit eng angebunden an ihren Verwendungszweck gut aufgehoben.

In der weiter unten skizzierten E-Commerce Anwendung wären das z.B. Seiten wie Warenkorb, Checkout, Produktübersicht- und Produktdetailseite.

Widgets

In sich gekapselte, größere Sektionen auf einer Seite können als Widgets angelegt werden.

Wenn ein UI-Block nicht seitenspezifisch, also generisch und wiederverwendbar ist, macht es Sinn ihn als Widget anzulegen.

Da Widgets eigene Fachlogik, spezifische Konfigurationen und Services besitzen und aus mehreren Komponenten bestehen können, macht es Sinn diese in Slices einzuteilen, die wiederum in Segments zu unterteilt sind.

Header und Footer wären typische Beispiele für ein Widget oder auch Sektionen mit ähnlichen Produkten.

Feature

Ein Feature beschreibt eine konkrete Funktionalität der Anwendung. Typischerweise eine Nutzerinteraktion, die wiederverwendbar ist, oder so auch an anderer Stelle genutzt werden könnte. Ein erster Blick in den Feature-Layer sollte einem direkt einen Überblick über die wichtigste Funktionalität bzw. Nutzer Mehrwert der Anwendung geben.

Auch hier macht die Unterteilung in Slices und dann weiter in Segments Sinn.

Interaktionselemente wie ein "Kaufen"- oder "Favoriten"-Button oder die Warenkorbvorschau im Headerbereich machen als Feature Sinn.

Entities

Entities sind alle Objekte, die für die Geschäftslogik unerlässlich sind.

Dabei geht es hier nicht nur um die Typdefinitionen, sondern auch um die damit verbundene Geschäftslogik und Backend-Anbindung. Sollte eine Entity eine spezifische Darstellung in der Anwendung haben, macht es Sinn, diese hier zu verordnen.

Bei einer E-Commerce Anwendung wären das z.B. Produkt, Warenkorb oder Kunde.

Shared

Der Shared Layer ist nicht in Slices unterteilt, da sich hier nur sehr generische Komponenten, Bibliotheken und Services mit hoher Wiederverwendbarkeit und minimalen äußeren Abhängigkeiten befinden sollten und keine Einteilung in Fachlogik.

Innerhalb der Segments von Shared darf es, wie in allen anderen Layern auch, Abhängigkeiten geben.

In der Praxis finden wir hier z.B. Formatierungshelfer und sehr generische UI-Komponenten wie Dialoge, Buttons oder Tooltips. Genauso wie wiederverwendbare Abstraktionen für die Anbindung an Schnittstellen.

Slices

Slices stellen die Gruppierung nach Fachlichkeit in jedem Layer dar. Über die Benennung gibt es keine Vorgaben, jedoch sollte der fachliche Kontext dabei berücksichtigt und darauf geachtet werden, dass der Code gut navigierbar ist. Slices sollten lose gekoppelt und weder Abhängigkeiten im selben noch auf darüberliegende Layer haben. Der Grad der Kohäsion dagegen sollte hoch sein.

Segments

Im Gegensatz zu Slices sind Segments nicht nach ihrem fachlichen Zweck gruppiert, sondern nach ihrem technischen.

Es gibt hier keine strikten Vorgaben darüber, welche Segments in einer Anwendung verwendet werden sollten oder über deren Benennung. Als Leitlinie macht aber eine einheitliche Segmentierung über alle Slices der Anwendung Sinn.

FSD schlägt folgende Segments vor:

OrdnerBeschreibung
uiBenutzeroberflächen, UI-Komponenten mit Styles und Formatierung
apiBackend Anbindungen oder Schnittstellen zu externe Services
modelDatentypen und Schemata State-Management
libHilfs-Bibliotheken, die von mehreren Modulen verwendet werden
configKonfigurationen und Feature-Flags

Abhängigkeiten mit klarer Richtung

Als praktisches Beispiel habe ich hier eine Angular Anwendung erstellt, die eine rudimentäre E-Commerce-Lösung abbildet:

Feature-Sliced Design Sample project structure

Hier sehen wir, dass alle Pfeile zwischen den Layern strikt von oben nach unten verlaufen. Außerdem gibt es zwischen den Slices eines Layers keine Beziehungen.

Dadurch, dass die Abhängigkeiten aller Komponenten zueinander klar geregelt sind und nur in eine Richtung erfolgen darf, beseitigen wir Risiken von zirkulären Abhängigkeiten und zu enger Kopplung.

Im Sinne einer “ordentlichen Anwendungsarchitektur” kommen wir unseren Zielen schon etwas näher:

  • Klarheit und Verständlichkeit: Die Einteilung in Layer, Slices und Segments ist sowohl fachlich als auch technisch geregelt, so sollte das Was und Wie einer Komponente klar und die Navigation innerhalb der Struktur erleichtert sein.
  • Skalierbarkeit: FSD hat ein klares Konzept, wie Anwendungen zerteilt und in wiederverwendbaren Komponenten organisiert werden können. Außerdem eignet sich die Struktur hervorragend für besonders große und komplexe Anwendungen.
  • Flexibilität: Durch Entkopplung von Abhängigkeiten können Komponenten verändert oder entfernt werden, ohne unvorhersehbare oder schwer zu durchschauende Seiteneffekte.
  • Wartbarkeit: Auch hier ist die Entkopplung von Abhängigkeiten ein entscheidender Faktor. Darüber hinaus hilft die klar definierte Richtung der Abhängigkeiten Fehler einzugrenzen.
  • Konsistenz: Dadurch, dass FSD einige Regeln und Namenskonventionen vorgibt und gleiche Konzepte auf verschiedenen Ebenen anwendet, haben wir eine einheitliche Anwendungsstruktur.

Diese Effekte setzen natürlich ein einheitliches Verständnis im Team über die Architekturvorgaben und FSD voraus, so wie das Commitment diese einzuhalten.

Regeln brauchen Kontrolle

Glücklicherweise müssen wir uns bei der Entwicklung nicht darauf verlassen, dass alle Beteiligten die Regeln kennen und sich daran halten. ESLint, das in den meisten Frontend Projekten ohnehin schon zur Kontroller der Einhaltung von Code-Styles und -Standards eingesetzt wird, kann mit feature-sliced/eslint-config so erweitert werden, dass Verstöße gegen die Beziehungsregeln von FSD moniert werden.

Noch einen Schritt weiter geht dabei die Bibliothek steiger. Hier werden über die Kontrolle der Abhängigkeiten hinaus auch Namens-Konventionen und allgemeine FSD-spezifische Best Practices überprüft, wie z.B. ob ein Widget wiederverwendet wird, ob Slices im entsprechendem Layer erlaubt sind oder zu viele davon verwendet werden uvm.

Um die Erstellung von Ordnern zu erleichtern und gleich Barrel-Files an der richtigen Stelle anzulegen, kann eine praktische CLI-Bibliothek genutzt werden. Es gibt auch schon Plugins für IntelliJ und VS Code.

Ist Feature-Sliced Design die Rettung?

Nur wenige Frontend-Frameworks und Bibliotheken geben einen strikten Regelsatz vor, wie Anwendungen organisiert sein sollten. Und das ist auch gut so. Führt aber auch dazu, dass Anwendungen mit der Zeit zum Wildwuchs tendieren, schwer wartbar werden und für neue Teammitglieder undurchdringlich erscheinen. Fehlerraten häufen sich und die Entwicklungszeit für neue Features steigt mit der Komplexität der Software.

Selbst wenn für das Projekt schon Regeln und Konventionen definiert wurden, sind diese oft nur projektspezifisch und müssen beim Onboarding erst noch verinnerlicht werden.

FSD schreibt sich auf die Fahne eine projekt- und technologie-übergreifende Methodik bereitzustellen, die sich an gängigen Best-Practices orientiert und in der Praxis bewährt hat.

Wird diese Projektübergreifend angewendet, spart man sich Diskussionen über Architektur-Entscheidungen und hat eine einheitliche Projektlandschaft, in der sich Mitarbeitende schnell zurechtfinden.

Ganz so einfach ist es natürlich nicht und das wird schnell klar, wenn man sich Referenzprojekte nach FSD anschaut oder eigene Praxiserfahrungen damit sammelt.

Diese Projekte sind in der Regel nicht so einheitlich, wie man sich das wünschen würde. Man merkt schnell, dass die Frage, ob etwas ein Feature, ein Widget oder doch besser eine Entity ist, manchmal etwas Interpretationsspielraum zulässt.

Gerade die Einschränkung, nur Code in andere Layer zu extrahieren, wenn dieser auch an mehreren Stellen wiederverwendet wird und ansonsten im entsprechenden Slice der Page zu halten kann dazu führen, dass Komponenten umher geschoben werden oder eben nicht mehr einheitlich navigierbar sind.

Bei manchen Vorgaben macht es durchaus Sinn, im Team bewusst über Abweichungen zu sprechen und diese schriftlich im Projekt festzuhalten.

Was lernen wir aus Feature-Sliced Design und sollten wir es in unserem nächsten Projekt einsetzen?

Die Ansätze von FSD sind für jedes Frontend-Projekt enorm wertvoll!

Gerade wenn man sich noch keine Gedanken über eine grundlegende Architektur gemacht hat und nicht weiß, wie man man seine Anwendung strukturieren sollte.

Eine klare Gliederung in Features, also was der Code tut, und in Technologie, also wie der Code etwas tut, macht in jedem Fall Sinn. Die Kohärenz dabei hochzuhalten, ist ebenso ein sehr sinnvoller Ansatz.

Abhängigkeiten von Modulen über Regeln klar zu definieren, hilft dabei wartbare und robuste Anwendungen zu entwickeln und wird von einigen Frameworks wie NX out-of-the Box unterstützt oder kann schnell über eine Bibliothek wie eslint-plugin-boundaries in jedem Projekt eingesetzt werden.

Ob es gleich eine umfangreiche Methodik wie FSD sein muss, hängt auch davon ab, wie groß und wie langlebig das Projekt sein wird. Wenn man eine kleinteilige Micro Frontend Architektur, eine Website ohne komplexere Business-Logik oder einen kurzlebigen Proof-Of-Concept aufbaut, ist die Granularität von FSD vielleicht überdimensioniert.

In jedem Fall sollte man sich bei jedem Projekt Gedanken über die Architektur machen und dabei hilft es sicherlich, sich an erprobten Best Practices, wie sie z.B. in FSD definiert sind, zu orientieren.

Weiterführende Informationen zu FSD finden sich auf der Informationsseite der Community.

|

Beitrag teilen

//

Weitere Artikel in diesem Themenbereich

Entdecke spannende weiterführende Themen und lass dich von der codecentric Welt inspirieren.

//

Gemeinsam bessere Projekte umsetzen.

Wir helfen deinem Unternehmen.

Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.

Hilf uns, noch besser zu werden.

Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.