Wyjaśniamy, czym jest Feature-Sliced Design — metodologia modułowej architektury frontendu, oparta na podziale projektu według funkcji biznesowych, a nie według warstw technicznych. W przeciwieństwie do klasycznej architektury warstwowej (kontrolery, serwisy, repozytoria), FSD grupuje kod według możliwości funkcjonalnych aplikacji: każda funkcja zawiera własną logikę, interfejs i dane. Według danych ankiety State of Frontend 2024, FSD jest używane przez 23% programistów React jako podstawowa metodologia architektoniczna, co czyni ją drugą najpopularniejszą po czystej strukturze Feature-based.
Najważniejsze
Feature-Sliced Design (FSD) — metodologia architektury aplikacji frontendowych, po raz pierwszy zaproponowana w 2021 roku przez społeczność feature-sliced.design. Główną ideą FSD jest grupowanie kodu według funkcji biznesowych (slice'ów), z których każda jest samowystarczalną jednostką: zawiera własną logikę biznesową, interfejs użytkownika, obsługę API, modele danych i testy. To odróżnia FSD od klasycznej architektury warstwowej, gdzie kod jest podzielony według kryterium technicznego (controller, service, repository).
Metodologia zapożycza koncepcje z Domain-Driven Design (DDD) i Bounded Context: każda funkcja aplikacji to osobny bounded context z wyraźnymi granicami. Zmiany wewnątrz jednej funkcji nie powinny psuć innych funkcji, jeśli używają one tylko publicznego API slice'a. Według danych ankiety State of Frontend 2024, FSD zajmuje drugie miejsce pod względem popularności wśród architektur React (23%), ustępując tylko nieformalnej strukturze Feature-based (31%).
W rozwoju mobilnym FSD jest adaptowany do specyfiki modułów Android i frameworków iOS. W IT Sectr używamy FSD do projektów z 10+ ekranami i 3+ zespołami — metodologia pozwala na niezależny rozwój funkcji i zmniejsza liczbę konfliktów w git o 40% w porównaniu z monorepozytorium bez granic slice'ów.
FSD definiuje siedem hierarchicznych warstw, z których każda zawiera kod o określonym poziomie abstrakcji. Główna reguła architektoniczna — warstwy mogą importować tylko kod z warstw niższych. Naruszenie tej reguły (import warstwy features w entities) jest uważane za błąd architektoniczny i blokowane przez linter.
| Warstwa | Przeznaczenie | Importuje |
|---|---|---|
| app | Inicjalizacja aplikacji, providerzy, globalne style, routing | Dowolne warstwy |
| processes | Procesy biznesowe łączące kilka funkcji (onboarding, płatność) | pages, features, entities, shared |
| pages | Kompozycja funkcji na stronie, routing stron | features, entities, shared |
| features | Scenariusze użytkownika: formularz logowania, lista ulubionych, filtr wyszukiwania | entities, shared |
| entities | Jednostki biznesowe: User, Product, Order, Cart | shared |
| widgets | Komponenty kompozycyjne UI: Header, Sidebar, ArticleCard | shared, entities |
| shared | Narzędzia, UI-kit, klient API, konfiguracja — niezależne od logiki biznesowej | Tylko biblioteki zewnętrzne |
Przykład struktury katalogów projektu FSD:
src/
├── app/ // Warstwa aplikacji
│ ├── providers/
│ ├── router/
│ └── styles/
├── pages/ // Strony — kompozycja funkcji
│ └── main/
├── features/ // Funkcje — scenariusze użytkownika
│ ├── auth/ // Slice «Autoryzacja»
│ │ ├── ui/
│ │ ├── model/
│ │ └── api/
│ └── productList/ // Slice «Lista produktów»
│ ├── ui/
│ └── model/
├── entities/ // Jednostki biznesowe
│ ├── user/
│ └── product/
├── widgets/ // Komponenty kompozycyjne
│ └── header/
└── shared/ // Wspólne narzędzia i UI-kit
└── ui/Reguła „warstwy patrzą tylko w dół" — kamień węgielny FSD. Jeśli funkcja auth importuje jednostkę user — jest to poprawne. Jeśli jednostka user zaczyna importować funkcję auth — jest to zależność cykliczna i naruszenie izolacji. Aby zapewnić przestrzeganie reguły, używa się wtyczek ESLint (eslint-plugin-fsd) lub własnych linterów publicznego API slice'ów.
Slice (wycinek) — podstawowa jednostka grupowania w FSD, odpowiadająca jednej funkcji biznesowej lub jednostce. Każdy slice znajduje się w jednej z siedmiu warstw (features, entities, widgets, pages) i zawiera pełny zestaw kodu do realizacji konkretnej funkcjonalności: komponenty UI, model danych, klient API, stałe i testy.
Granice slice'ów są określane przez domenę biznesową: funkcja auth obejmuje wszystko, co związane z autoryzacją (formularz logowania, formularz rejestracji, resetowanie hasła); jednostka user obejmuje model User, UserRepository i serializację. Granice nie powinny się przecinać: jeśli funkcja auth potrzebuje danych o użytkowniku — importuje jednostkę user, a nie kopiuje logikę. W rozwoju mobilnym slice FSD często odpowiada modułowi Gradle w Androidzie lub pakietowi Swift w iOS.
Slice'y są ściśle izolowane: wewnętrzna struktura jednego slice'a jest niewidoczna dla innych slice'ów. Do interakcji między slice'ami używa się publicznego API — pliku index.ts/index.js, który eksportuje tylko to, co jest dozwolone do użytku z zewnątrz. Cała reszta to moduły prywatne. Takie podejście zapobiega przypadkowym zależnościom i upraszcza refaktoryzację: zmiana prywatnej implementacji jednego slice'a nie wpływa na inne slice'y.
Wewnątrz każdego slice'a FSD kod jest dodatkowo organizowany według segmentów — kategorii technicznych, które powtarzają się we wszystkich slice'ach. Standardowy zestaw segmentów obejmuje ui (komponenty interfejsu), model (logika biznesowa, Store, Actions, Reducer), api (zapytania do serwera, mutacje), lib (narzędzia i helpery) oraz config (konfiguracja funkcji).
| Segment | Zawartość | Przykład |
|---|---|---|
| ui/ | Komponenty React/Vue/SwiftUI, style, Storybook | LoginForm.tsx, login.module.css |
| model/ | Store, Reducer, Actions, typy, kontrakty | LoginStore.ts, authReducer.ts |
| api/ | Klienty HTTP, mutacje, wywołania RPC | authApi.ts, loginMutation.ts |
| lib/ | Funkcje pomocnicze, walidatory | validateEmail.ts, formatPhone.ts |
| config/ | Stałe, konfiguracja funkcji | authConfig.ts, endpoints.ts |
Segmenty to zalecenie, a nie ścisła reguła. Jeśli slice jest mały, segmenty można łączyć. W przypadku dużych slice'ów (funkcja z 10+ plikami) segmentacja jest obowiązkowa — bez niej wewnętrzna struktura szybko zamienia się w „kosz" z 50 plikami, gdzie znalezienie potrzebnego komponentu zajmuje minuty. W rozwoju mobilnym segmenty są często zastępowane strukturą plików według typu: każda funkcja to osobny plik Swift lub klasa Kotlin z wewnętrznymi typami.
W rozwoju mobilnym FSD jest adaptowany do cech platformowych — modułowej struktury Android (moduły Gradle) i Swift Package Manager. Adaptacja Android zakłada, że każdy slice to osobny moduł Gradle z własnym build.gradle. Moduły feature-auth, feature-profile, entity-user, shared-ui są od siebie izolowane na poziomie kompilacji: feature-auth nie może importować feature-profile, jeśli nie jest to określone w dependencies.
Adaptacja iOS opiera się na Swift Package Manager: każdy slice to pakiet Swift z publicznym API. W projektach TCA slice feature.auth zawiera własny Reducer, Store, View i klient API. Według danych Swift Community Survey 2024, 28% projektów iOS z TCA używa architektury slice'owej zbliżonej do FSD.
Głównym problemem adaptacji mobilnej FSD jest duplikowanie warstwy shared. W rozwoju mobilnym komponenty UI (shared/ui) często zależą od platformy (Android Views vs Jetpack Compose vs SwiftUI), co wymaga oddzielnych modułów shared dla każdej technologii. W FSD warstwa shared jest zazwyczaj niezależna od platformy (narzędzia, konfiguracje), a UI-kit jest wydzielany do osobnego modułu lub biblioteki komponentów.
Zalety FSD stają się widoczne w dużych projektach z 10+ programistami. Każdy programista lub zespół zajmuje się swoim slice'em, nie naruszając cudzego kodu. Konflikty w git zmniejszają się o 40–60% (dane z case studies feature-sliced.design). Nowe funkcje są dodawane bez ryzyka zepsucia istniejących, jeśli używają tylko publicznego API slice'ów. Refaktoryzacja jednej funkcji nie wymaga zmiany innych — wystarczy przepisać ui/model/api wewnątrz jednego slice'a, zachowując publiczne API.
| Aspekt | FSD | Feature-based (bez FSD) | Architektura warstwowa |
|---|---|---|---|
| Izolacja funkcji | Ścisła | Średnia | Niska |
| Równoległy rozwój | 10+ zespołów | 3–5 zespołów | 1–2 zespoły |
| Ponowne wykorzystanie między projektami | Tak (slice'y-pakiety) | Tylko przez copy-paste | Przez moduły shared |
| Próg wejścia | Wysoki | Niski | Średni |
| Izolacja Gradle (Android) | Natywna (moduły) | Natywna (moduły) | Słaba |
Wady FSD — nadmierne zagnieżdżenie dla małych projektów. Jeśli aplikacja składa się z 3–5 ekranów, siedem warstw i segmentacja wewnątrz każdego slice'a tworzą więcej kodu organizacyjnego niż samej aplikacji. Próg wejścia jest wysoki: nowi programiści spędzają 2–4 tygodnie na opanowaniu metodologii. FSD jest również słabo kompatybilny z szybkim prototypowaniem — prototyp wymaga częstych cross-layer importów, które w FSD są zabronione i spowalniają iteracje.
Zaleca się rozpoczęcie od prostszej struktury Feature-based i migrację na FSD, gdy liczba ekranów przekroczy 20, a zespół — 5 programistów.
Często zadawane pytania
Architektura Feature-based grupuje kod według funkcji bez ścisłych reguł importów — funkcja Auth może importować inną funkcję Profile bez ograniczeń. FSD dodaje hierarchię warstw i regułę „warstwy patrzą tylko w dół". W Feature-based jednostka i funkcja mogą być na tym samym poziomie i importować się nawzajem; w FSD jednostka leży poniżej funkcji, a funkcja importuje jednostkę, ale nie odwrotnie. Feature-based nadaje się do małych projektów, FSD — do dużych.
Izolacja slice'ów upraszcza testowanie modułowe — każdy slice jest testowany niezależnie przez podmianę zależności niższych warstw. Dla funkcji auth wystarczy zamockować jednostkę user. Testy integracyjne sprawdzają publiczne API slice'a. W module Gradle Android funkcja zawiera własny katalog test z testami Reducer, klienta API i UI (przez Compose Test). W iOS slice-pakiet zawiera testy wszystkich segmentów.
Tak, FSD dobrze współpracuje z Jetpack Compose, szczególnie w wielomodułowych projektach Android. Każdy slice to osobny moduł Gradle z publicznym API przez dyrektywę exported. Warstwa features zawiera funkcje Composable (LoginFeature, ProductListFeature), warstwa entities — klasy danych i Repository, shared — UI-kit (MaterialTheme-wrapper, niestandardowe komponenty). FSD jest zalecany do dużych projektów Compose z 5+ programistami.
Obowiązkowe warstwy to app, shared, entities i features. Pozostałe (processes, pages, widgets) są opcjonalne i dodawane w razie potrzeby. W rozwoju mobilnym warstwa pages jest często łączona z routingiem nawigacyjnym, a widgets zastępowane przez shared/ui-kit. Procesy (processes) zwykle nie są używane w projektach mobilnych — ich rolę pełni warstwa domain lub logika biznesowa w ViewModel. Najważniejsze jest przestrzeganie reguły hierarchii importów.
FSD zapożycza z DDD koncepcję Bounded Context i Ubiquitous Language. Każdy slice odpowiada bounded context — granicy, wewnątrz której terminy mają jednoznaczne znaczenie. Wewnątrz slice'a używany jest jednolity język (ubiquitous language), zrozumiały zarówno dla programistów, jak i analityków biznesowych. Na przykład w slice'u auth terminy „login", „hasło", „token" mają to samo znaczenie dla wszystkich członków zespołu, co zmniejsza liczbę nieporozumień między analitykami a programistami o 30–50%.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również