Explicăm ce este Feature-Sliced Design — o metodologie de arhitectură modulară frontend, bazată pe împărțirea proiectului după funcționalități de business, nu după straturi tehnice. Spre deosebire de arhitectura clasică pe straturi (controlere, servicii,Repository-uri), FSD grupează codul după capacitățile funcționale ale aplicației: fiecare funcționalitate conține propria logică, interfață și date. Conform datelor sondajului State of Frontend 2024, FSD este folosit de 23% dintre dezvoltatorii React ca metodologie arhitecturală principală, ceea ce o face a doua ca popularitate după structura pur Feature-based.
Principalele puncte
Feature-Sliced Design (FSD) — o metodologie de arhitectură a aplicațiilor frontend, propusă pentru prima dată în 2021 de comunitatea feature-sliced.design. Ideea principală a FSD — gruparea codului după funcționalități de business (slice-uri), fiecare fiind o unitate autosuficientă: conține propria logică de business, interfață cu utilizatorul, lucru cu API, modele de date și teste. Aceasta deosebește FSD de arhitectura clasică pe straturi, unde codul este împărțit după criterii tehnice (controller, service, repository).
Metodologia împrumută concepte din Domain-Driven Design (DDD) și Bounded Context: fiecare funcționalitate a aplicației este un bounded context separat cu granițe clare. Modificările în interiorul unei funcționalități nu ar trebui să strice alte funcționalități, dacă acestea folosesc doar API-ul public al slice-ului. Conform datelor sondajului State of Frontend 2024, FSD ocupă locul doi ca popularitate printre arhitecturile React (23%), cedând doar structurii informale Feature-based (31%).
În dezvoltarea mobilă, FSD se adaptează la specificul modulelor Android și framework-urilor iOS. În IT Sectr folosim FSD pentru proiecte cu 10+ ecrane și 3+ echipe — metodologia permite dezvoltarea independentă a funcționalităților și reduce numărul conflictelor în git cu 40% comparativ cu un monorepository fără granițe de slice-uri.
FSD definește șapte straturi ierarhice, fiecare conținând cod de un anumit nivel de abstractizare. Regula arhitecturală principală — straturile pot importa doar cod din straturile inferioare. Încălcarea acestei reguli (importul stratului features în entities) este considerată o eroare arhitecturală și este blocată de linter.
| Strat | Destinație | Importă |
|---|---|---|
| app | Inițializarea aplicației, provideri, stiluri globale, rutare | Orice straturi |
| processes | Procese de business care combină mai multe funcționalități (onboarding, plată) | pages, features, entities, shared |
| pages | Compoziția funcționalităților pe pagină, rutarea paginilor | features, entities, shared |
| features | Scenarii de utilizator: formular de autentificare, listă de favorite, filtru de căutare | entities, shared |
| entities | Entități de business: User, Product, Order, Cart | shared |
| widgets | Componente compoziționale UI: Header, Sidebar, ArticleCard | shared, entities |
| shared | Utilitare, UI-kit, client API, configuri — independent de logica de business | Doar biblioteci externe |
Exemplu de structură de directoare a unui proiect FSD:
src/
├── app/ // Stratul aplicației
│ ├── providers/
│ ├── router/
│ └── styles/
├── pages/ // Pagini — compoziția funcționalităților
│ └── main/
├── features/ // Funcționalități — scenarii de utilizator
│ ├── auth/ // Slice «Autentificare»
│ │ ├── ui/
│ │ ├── model/
│ │ └── api/
│ └── productList/ // Slice «Listă produse»
│ ├── ui/
│ └── model/
├── entities/ // Entități de business
│ ├── user/
│ └── product/
├── widgets/ // Componente compoziționale
│ └── header/
└── shared/ // Utilitare comune și UI-kit
└── ui/Regula „straturile privesc doar în jos" — piatra de temelie a FSD. Dacă funcționalitatea auth importă entitatea user — este corect. Dacă entitatea user începe să importe funcționalitatea auth — este o dependență ciclică și o încălcare a izolării. Pentru asigurarea respectării regulii, se folosesc pluginuri ESLint (eslint-plugin-fsd) sau lintere proprii ale API-ului public al slice-urilor.
Slice-ul — unitatea principală de grupare în FSD, corespunzând unei funcționalități de business sau entități. Fiecare slice se află în interiorul unuia dintre cele șapte straturi (features, entities, widgets, pages) și conține setul complet de cod pentru implementarea unei funcționalități concrete: componente UI, model de date, client API, constante și teste.
Granițele slice-urilor sunt determinate de domeniul de business: funcționalitatea auth include tot ce ține de autentificare (formular de autentificare, formular de înregistrare, resetare parolă); entitatea user include modelul User, UserRepository și serializarea. Granițele nu trebuie să se suprapună: dacă funcționalitatea auth are nevoie de date despre utilizator — importă entitatea user, nu copiază logica. În dezvoltarea mobilă, un slice FSD corespunde adesea unui modul Gradle în Android sau unui pachet Swift în iOS.
Slice-urile sunt strict izolate: structura internă a unui slice este invizibilă pentru alte slice-uri. Pentru interacțiunea între slice-uri se folosește API-ul public — fișierul index.ts/index.js care exportă doar ceea ce este permis pentru utilizare din exterior. Restul sunt module private. Această abordare previne dependențele accidentale și simplifică refactorizarea: modificarea implementării private a unui slice nu afectează alte slice-uri.
În interiorul fiecărui slice FSD, codul este organizat suplimentar pe segmente — categorii tehnice care se repetă în toate slice-urile. Setul standard de segmente include ui (componente de interfață), model (logică de business, Store, Actions, Reducer), api (cereri către server, mutații), lib (utilitare și helperi) și config (configurarea funcționalității).
| Segment | Conținut | Exemplu |
|---|---|---|
| ui/ | Componente React/Vue/SwiftUI, stiluri, Storybook | LoginForm.tsx, login.module.css |
| model/ | Store, Reducer, Actions, tipuri, contracte | LoginStore.ts, authReducer.ts |
| api/ | Clienți HTTP, mutații, apeluri RPC | authApi.ts, loginMutation.ts |
| lib/ | Funcții ajutătoare, validatori | validateEmail.ts, formatPhone.ts |
| config/ | Constante, configurarea funcționalității | authConfig.ts, endpoints.ts |
Segmentele sunt o recomandare, nu o regulă strictă. Dacă slice-ul este mic, segmentele pot fi combinate. Pentru slice-uri mari (funcționalitate cu 10+ fișiere), segmentarea este obligatorie — fără ea, structura internă se transformă rapid într-un „coș" de 50 de fișiere, unde găsirea componentei necesare durează minute. În dezvoltarea mobilă, segmentele sunt adesea înlocuite cu o structură de fișiere pe tip: fiecare funcționalitate este un fișier Swift separat sau o clasă Kotlin cu tipuri interne.
În dezvoltarea mobilă, FSD se adaptează la particularitățile platformei — structura modulară Android (module Gradle) și Swift Package Manager. Adaptarea Android presupune că fiecare slice este un modul Gradle separat cu propriul build.gradle. Modulele feature-auth, feature-profile, entity-user, shared-ui sunt izolate între ele la nivel de compilare: feature-auth nu poate importa feature-profile dacă nu este specificat în dependencies.
Adaptarea iOS se bazează pe Swift Package Manager: fiecare slice este un pachet Swift cu API public. În proiectele TCA, slice-ul feature.auth conține propriul Reducer, Store, View și client API. Conform datelor Swift Community Survey 2024, 28% dintre proiectele iOS cu TCA folosesc o arhitectură pe slice-uri apropiată de FSD.
Principala problemă a adaptării mobile FSD — duplicarea stratului shared. În dezvoltarea mobilă, componentele UI (shared/ui) depind adesea de platformă (Android Views vs Jetpack Compose vs SwiftUI), ceea ce necesită module shared separate pentru fiecare tehnologie. În FSD, stratul shared este de obicei independent de platformă (utilitare, configuri), iar UI-kit este externalizat într-un modul separat sau o bibliotecă de componente.
Avantajele FSD devin vizibile în proiecte mari cu 10+ dezvoltatori. Fiecare dezvoltator sau echipă se ocupă de propriul slice, fără a atinge codul altora. Conflictele în git se reduc cu 40–60% (date din case studies feature-sliced.design). Funcționalități noi sunt adăugate fără riscul de a strica existentele, dacă folosesc doar API-ul public al slice-urilor. Refactorizarea unei funcționalități nu necesită modificarea altora — este suficient să rescrii ui/model/api în interiorul unui singur slice, păstrând API-ul public.
| Aspect | FSD | Feature-based (fără FSD) | Arhitectură pe straturi |
|---|---|---|---|
| Izolarea funcționalităților | Strictă | Medie | Scăzută |
| Dezvoltare paralelă | 10+ echipe | 3–5 echipe | 1–2 echipe |
| Reutilizare între proiecte | Da (slice-uri-pachete) | Doar prin copy-paste | Prin module shared |
| Prag de intrare | Ridicat | Scăzut | Mediu |
| Izolare Gradle (Android) | Nativă (module) | Nativă (module) | Slabă |
Dezavantajele FSD — cuibărire excesivă pentru proiecte mici. Dacă aplicația constă din 3–5 ecrane, șapte straturi și segmentarea în interiorul fiecărui slice creează mai mult cod organizațional decât aplicația în sine. Pragul de intrare este ridicat: dezvoltatorii noi petrec 2–4 săptămâni pentru a însuși metodologia. De asemenea, FSD este slab compatibil cu prototiparea rapidă — prototipul necesită importuri frecvente cross-layer, care sunt interzise în FSD și încetinesc iterațiile.
Se recomandă începerea cu o structură Feature-based mai simplă și migrarea la FSD când numărul de ecrane depășește 20, iar echipa — 5 dezvoltatori.
Întrebări frecvente
Arhitectura Feature-based grupează codul pe funcționalități fără reguli stricte de import — funcționalitatea Auth poate importa o altă funcționalitate Profile fără restricții. FSD adaugă o ierarhie de straturi și regula „straturile privesc doar în jos". În Feature-based, entitatea și funcționalitatea pot fi la același nivel și se pot importa reciproc; în FSD, entitatea se află sub funcționalitate, iar funcționalitatea importă entitatea, dar nu invers. Feature-based este potrivit pentru proiecte mici, FSD — pentru proiecte mari.
Izolarea slice-urilor simplifică testarea modulară — fiecare slice este testat independent prin înlocuirea dependențelor straturilor inferioare. Pentru funcționalitatea auth este suficient să faci mock la entitatea user. Testele de integrare verifică API-ul public al slice-ului. În modulul Gradle Android, funcționalitatea conține propriul director de teste cu teste pentru Reducer, client API și UI (prin Compose Test). În iOS, pachetul-slice include teste pentru toate segmentele.
Da, FSD se combină bine cu Jetpack Compose, în special în proiecte Android multi-modul. Fiecare slice este un modul Gradle separat cu API public prin directiva exported. Stratul features conține funcționalități Composable (LoginFeature, ProductListFeature), stratul entities — clase de date și Repository, shared — UI-kit (MaterialTheme-wrapper, componente personalizate). FSD este recomandat pentru proiecte mari Compose cu 5+ dezvoltatori.
Straturile obligatorii sunt app, shared, entities și features. Celelalte (processes, pages, widgets) sunt opționale și se adaugă după necesitate. În dezvoltarea mobilă, stratul pages este adesea combinat cu rutarea de navigare, iar widgets sunt înlocuite cu shared/ui-kit. Procesele (processes) de obicei nu sunt folosite în proiecte mobile — rolul lor este îndeplinit de stratul domain sau logica de business din ViewModel. Principalul este respectarea regulii ierarhiei de import.
FSD împrumută din DDD conceptul de Bounded Context și Ubiquitous Language. Fiecare slice corespunde unui bounded context — o graniță în interiorul căreia termenii au un sens univoc. În interiorul slice-ului se folosește un limbaj unitar (ubiquitous language), înțeles atât de dezvoltatori, cât și de analiștii de business. De exemplu, în slice-ul auth, termenii „login", „parolă", „token" au același sens pentru toți membrii echipei, ceea ce reduce numărul neînțelegerilor între analiști și dezvoltatori cu 30–50%.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și