Poznaj podejście Vertical Slice Architecture i zobacz, jak uprościć rozwój aplikacji, zwiększyć czytelność kodu i pozbyć się niepotrzebnych warstw.

Gdy rozmawiamy o architekturze aplikacji, często słyszymy o warstwach. Warstwa prezentacji, logiki biznesowej, dostępu do danych… brzmi znajomo? Jeśli spędziłeś choć trochę czasu w kodzie, który był rozwijany latami, to wiesz, że te warstwy, zamiast porządkować – potrafią skutecznie komplikować. I tutaj właśnie na scenę wchodzi Vertical Slice Architecture.
Warstwy są przeszłością?
W klasycznym podejściu nasze aplikacje przypominają cebulę. Każda warstwa coś robi, ale żeby wykonać prostą operację, musimy przejść przez kilka abstrakcji, klas pomocniczych, mapper-ów i interfejsów. Dodanie nowej funkcji bywa jak dłubanie w starej instalacji – nigdy nie wiesz, gdzie porazi cię prąd.
Vertical Slice Architecture podchodzi do tematu inaczej. Zamiast dzielić aplikację poziomo (na warstwy), dzielimy ją pionowo – na funkcjonalne wycinki. Każdy slice zawiera wszystko, co potrzebne do obsłużenia konkretnego przypadku użycia: logikę, dane wejściowe, walidację i dostęp do danych.
Przypadek użycia jako jednostka architektoniczna
W tej architekturze centralnym punktem nie jest warstwa, tylko use case. To on definiuje, co aplikacja robi i co jest potrzebne, żeby to zrobić dobrze. Przykład? Załóżmy, że chcemy dodać nowego użytkownika. Nie tworzymy osobno DTO, handlera, serwisu i repozytorium w trzech różnych folderach. Zamiast tego, tworzymy jeden spójny slice:
src/
│
├── users/
│ └── createUser/
│ ├── CreateUserCommand.ts
│ ├── CreateUserValidator.ts
│ ├── CreateUserHandler.ts
│ └── CreateUserResponse.tsWszystko, co potrzebne do wykonania operacji CreateUser, znajduje się w jednym miejscu. Możesz to czytać jak rozdział książki – od wejścia, przez walidację, aż po efekt końcowy.
Kod, który mówi za siebie
Spójrzmy na uproszczony przykład slice’a odpowiedzialnego za tworzenie użytkownika:
// CreateUserCommand.ts
export class CreateUserCommand {
constructor(
public readonly email: string,
public readonly password: string,
public readonly name: string
) {}
}
// CreateUserValidator.ts
export class CreateUserValidator {
validate(command: CreateUserCommand): string[] {
const errors: string[] = [];
if (!command.email.includes("@")) {
errors.push("Nieprawidłowy adres e-mail.");
}
if (command.password.length < 6) {
errors.push("Hasło musi mieć co najmniej 6 znaków.");
}
return errors;
}
}
// CreateUserHandler.ts
export class CreateUserHandler {
constructor(
private readonly userRepository: UserRepository
) {}
async handle(command: CreateUserCommand): Promise<CreateUserResponse> {
const user = new User(command.name, command.email, command.password);
await this.userRepository.save(user);
return new CreateUserResponse(user.id);
}
}
// CreateUserResponse.ts
export class CreateUserResponse {
constructor(
public readonly userId: string
) {}
}Po co to wszystko?
Vertical Slice Architecture to nie tylko zmiana struktury katalogów. To zmiana sposobu myślenia. Przestajesz projektować system wokół technologii (ORM, framework, wzorce warstw), a zaczynasz projektować go wokół problemów, które rozwiązujesz.
Zyskujesz:
- większą czytelność,
- łatwiejsze testowanie (testujesz tylko slice, nie zależności warstwowe),
- prostsze zmiany (zmieniasz tylko to, co dotyczy konkretnego use case’a).
Czy to działa w większych projektach?
Tak. Wręcz przeciwnie – im większy projekt, tym bardziej Vertical Slice Architecture błyszczy. Dzięki rozdzieleniu logiki na funkcjonalne jednostki łatwiej podzielić pracę w zespole, szybciej onboardować nowych programistów i unikać konfliktów merge’ów w nieskończonych serwisach “UserService”.
Ostatecznie chodzi o to, by kod był jak dobra dokumentacja – żeby dało się go czytać i rozumieć bez tłumacza. Vertical Slice Architecture temu sprzyja. Czy zawsze? Nie. Ale jeśli tworzysz aplikację, która rośnie, zmienia się i ma realne przypadki użycia – to warto spróbować.
Masz pytania albo sam stosujesz Vertical Slice w swoim projekcie? Daj znać w komentarzu.


Dodaj komentarz