A Vertical Slice Architecture é um estilo de arquitetura de software que organiza uma aplicação em torno de funcionalidades completas (features) em vez de organizá-la por camadas técnicas. Em outras palavras, em vez de separar o projeto em pastas como Controllers, Services, Repositories, Models e DTOs, ela agrupa tudo o que uma determinada funcionalidade precisa em um único lugar. A ideia central é que cada "fatia vertical" represente um caso de uso completo da aplicação, contendo toda a lógica necessária para executar aquela funcionalidade, desde a entrada da requisição até o acesso ao banco de dados e o retorno da resposta.
Para entender melhor, vale comparar com a arquitetura tradicional em camadas (Layered Architecture). Imagine que você precise implementar uma funcionalidade chamada "Cadastrar Cliente". Em uma arquitetura tradicional, você provavelmente criaria um CustomerController, um CustomerService, um CustomerRepository, um CustomerValidator, um CustomerDTO e talvez outras classes distribuídas em diferentes diretórios. Sempre que fosse alterar essa funcionalidade, precisaria navegar por várias pastas e arquivos espalhados pelo projeto. Com o passar do tempo, principalmente em sistemas grandes, isso faz com que mudanças simples exijam modificações em diversos lugares diferentes, aumentando o acoplamento e tornando a manutenção mais trabalhosa.
Na Vertical Slice Architecture, o pensamento é completamente diferente. Em vez de perguntar "em qual camada esse código pertence?", você pergunta "a qual funcionalidade esse código pertence?". Assim, tudo relacionado ao cadastro de clientes fica reunido em uma única pasta ou módulo. Dentro dela podem existir o comando de cadastro, o handler responsável pela lógica, o validador, o endpoint, os modelos específicos daquela funcionalidade e qualquer outra classe necessária. Se houver outra funcionalidade, como "Atualizar Cliente", ela terá sua própria fatia independente, mesmo que também trabalhe com clientes. Isso significa que diferentes funcionalidades não precisam compartilhar obrigatoriamente os mesmos serviços ou repositórios, podendo possuir implementações específicas quando isso fizer sentido.
O nome "Vertical Slice" vem justamente dessa ideia de cortar o sistema verticalmente. Enquanto arquiteturas tradicionais fazem cortes horizontais, separando apresentação, negócio e persistência em camadas independentes, a Vertical Slice corta o sistema de cima a baixo, formando fatias completas que atravessam todas essas camadas. Cada fatia é responsável por resolver um único caso de uso. Isso faz com que o sistema seja organizado em torno das necessidades do usuário e não da tecnologia utilizada.
Esse conceito está intimamente ligado aos princípios do Domain-Driven Design (DDD), do CQRS (Command Query Responsibility Segregation) e da Clean Architecture, embora não dependa deles. É muito comum encontrar projetos que utilizam Vertical Slice juntamente com o padrão Mediator, especialmente através da biblioteca MediatR no ecossistema .NET. Nesse cenário, cada requisição é representada por um Command ou Query, que é enviado ao Mediator. O Mediator encontra automaticamente o Handler responsável por aquela operação, mantendo o código desacoplado e facilitando a evolução da aplicação. Entretanto, a arquitetura não exige o uso do MediatR; ele apenas se encaixa muito bem nesse modelo.
Outro aspecto importante é que a Vertical Slice incentiva o isolamento entre funcionalidades. Se uma determinada feature precisar de uma consulta muito específica ao banco de dados, ela pode fazer essa consulta diretamente sem obrigar todo o sistema a utilizar um repositório genérico. Da mesma forma, se outra funcionalidade exigir uma regra de negócio diferente, ela pode implementar essa lógica sem impactar as demais. Isso reduz a tendência de criar enormes classes de serviço com centenas de métodos responsáveis por quase tudo na aplicação, um problema bastante comum em arquiteturas tradicionais.
Uma consequência interessante dessa abordagem é que o código costuma ficar mais fácil de entender. Quando um novo desenvolvedor entra no projeto e precisa alterar uma funcionalidade específica, normalmente basta abrir a pasta daquela feature para encontrar praticamente tudo o que precisa. Ele não precisa percorrer dezenas de diretórios tentando descobrir onde está cada parte da implementação. Isso reduz significativamente a carga cognitiva durante a manutenção.
A Vertical Slice também favorece o princípio da alta coesão. Todos os arquivos relacionados a um mesmo objetivo permanecem próximos, enquanto funcionalidades diferentes permanecem separadas. Em vez de compartilhar código prematuramente, essa arquitetura aceita um certo nível de duplicação quando isso torna as funcionalidades mais independentes. Esse é um dos pontos que costuma causar estranheza para quem está acostumado ao princípio DRY (Don't Repeat Yourself). Na Vertical Slice, pequenas duplicações podem ser preferíveis a criar abstrações genéricas que acabam acoplando partes do sistema que deveriam evoluir de forma independente.
Em projetos de APIs REST modernas, especialmente utilizando ASP.NET Core, é comum encontrar uma estrutura semelhante a esta:
Features/
Customers/
CreateCustomer/
Endpoint.cs
Command.cs
Handler.cs
Validator.cs
Response.cs
UpdateCustomer/
Endpoint.cs
Command.cs
Handler.cs
Validator.cs
DeleteCustomer/
Endpoint.cs
Command.cs
Handler.cs
Orders/
CreateOrder/
CancelOrder/
GetOrder/
Observe que não existe uma pasta global chamada Services ou Repositories obrigatoriamente. Cada funcionalidade possui apenas os arquivos necessários para resolver aquele caso de uso específico.
Essa arquitetura é especialmente vantajosa em sistemas que crescem continuamente, como plataformas SaaS, APIs corporativas, microsserviços e aplicações que recebem novas funcionalidades com frequência. Como cada feature é relativamente isolada, equipes diferentes conseguem trabalhar em funcionalidades distintas com menos conflitos de código e menor risco de quebrar partes não relacionadas do sistema.
Entretanto, a Vertical Slice não é uma solução universal. Em aplicações muito pequenas, ela pode parecer um exagero, já que uma estrutura tradicional talvez seja suficiente. Além disso, se utilizada sem critério, pode haver duplicação excessiva de código e dificuldade em identificar componentes que realmente deveriam ser compartilhados. O objetivo não é eliminar completamente reutilização, mas evitar abstrações prematuras que tornam o sistema mais complexo do que o necessário.
Hoje, a Vertical Slice Architecture vem ganhando bastante espaço no desenvolvimento de software moderno porque reflete uma mudança de mentalidade importante: organizar o código em torno do que o sistema faz, e não em torno das tecnologias utilizadas para implementá-lo. Em vez de pensar em controladores, serviços e repositórios como protagonistas da arquitetura, o foco passa a ser os casos de uso que entregam valor ao usuário. Essa mudança costuma resultar em código mais modular, mais fácil de manter, mais simples de testar e mais preparado para evoluir conforme novos requisitos surgem. Para desenvolvedores que trabalham com APIs, microsserviços, DDD, CQRS e arquiteturas modernas, compreender a Vertical Slice Architecture tornou-se uma habilidade bastante valorizada, justamente porque ela oferece uma forma prática de reduzir acoplamento e aumentar a clareza estrutural de aplicações de médio e grande porte.
Essa é a arquitetura Vertical Slice Architecture (Arquitetura de Fatia Vertical), combinada com padrões do CQRS (Command Query Responsibility Segregation).
Por que Vertical Slice? A organização não é por camada técnica (Controllers, Services, Repositories...), mas sim por feature/funcionalidade. Cada "fatia" contém tudo que aquela operação precisa:
Features/
Activities/
GetActivity/
ActivityResponse.cs
GetActivityEndpoint.cs
GetActivityQuery.cs
GetActivityQueryHandler.cs
CreateActivity/
CreateActivity.Command.cs
CreateActivity.Endpoint.cs
CreateActivity.Handler.cs
CreateActivity.Validator.cs
Por que CQRS? Dentro de cada slice, há separação explícita entre:
- Query → operação de leitura (
GetActivityQuery,GetActivityQueryHandler) - Command → operação de escrita (
CreateActivity.Command,CreateActivity.Handler) - Validator → validação da entrada (
CreateActivity.Validator) - Endpoint → exposição HTTP (
CreateActivity.Endpoint)
Isso sugere o uso de MediatR como mediador, padrão comum em projetos .NET com essa arquitetura.
Estrutura geral do projeto É uma Web API em .NET (Program.cs, appsettings.json), com:
Database/Entities— modelos de domínio (Activity.cs,Workout.cs)Features— lógica organizada por featureMiddleware— middlewares customizados
Important
Vantagem principal: Cada feature é autossuficiente e isolada — você modifica CreateActivity sem tocar em nada de GetActivity ou Workouts.
O Projeto completo seguindo fielmente a estrutura da imagem. Agora vou gerar todos os arquivos:26 arquivos, tudo certo. Agora vou zipar e disponibilizar:Projeto completo! Aqui está o que foi gerado — 26 arquivos seguindo fielmente a estrutura da imagem:
Para rodar localmente:
cd RunTracker.API
dotnet restore
dotnet runAcesse: http://localhost:5000/swagger
O que foi implementado:
| Slice | Arquivos |
|---|---|
GetActivity |
Query, QueryHandler, Response, Endpoint |
CreateActivity |
Command, Handler, Validator, Endpoint |
GetWorkout |
Query, QueryHandler, Response, Endpoint |
CreateWorkout |
Command, Handler, Validator, Endpoint |
Decisões técnicas:
- Carter para os endpoints (Minimal API por módulo, sem Controllers)
- MediatR como mediador entre endpoint e handler
- FluentValidation com validação inline no endpoint antes de despachar o comando
- Mapster para mapeamento automático Command → Entity e Entity → Response
- SQLite com
EnsureCreatedno startup — sem necessidade de rodar migrations manualmente - ExceptionHandlingMiddleware centraliza todos os erros com resposta JSON padronizada