Fatias de features agrupam tudo o que uma área de produto precisa em um diretório; pastas de camadas (components/, hooks/, screens/ na raiz do repositório) espalham código relacionado pela árvore. A divisão que você escolhe no primeiro dia determina o quão dolorosas serão as primeiras 50 features.
Fatias de Features (verticais) organizam por capacidade do produto - features/orders, features/inbox. Mudanças em Pedidos afetam arquivos sob uma única subárvore.
Camadas (horizontais) organizam por função técnica - components/, hooks/, screens/ globais. Cada feature espalha arquivos por múltiplas pastas de nível superior.
Expo Router app/ mapeia URLs para telas. Arquivos de rota devem permanecer como pontos de entrada finos; a lógica pesada vive em features/.
APIs públicas index.ts aplicam limites de importação - importações entre features usam @/features/orders, nunca @/features/orders/components/OrderRow.
components/ui/ compartilhado contém primitivos do sistema de design usados por muitas features; components/ da feature contém composição específica do produto.
Risco de duplicar linhas semelhantes entre features
Em Camadas
screens/, hooks/, components/ na raiz
Familiar para desenvolvedores web; fácil de encontrar "todos os hooks"
Importações entre pastas explodem; telas "god" emergem
Híbrido (recomendado)
components/ui/ + features/* + app/ fino
Primitivos compartilhados sem um cemitério global de componentes
Requer disciplina nas exportações de index.ts
# Em Camadas - bom para < 5 telas, doloroso em escalasrc/├── components/ # linhas, cards, modais de todas as features misturados├── hooks/├── screens/└── services/# Fatia de Feature - escala com a equipe e o número de featuressrc/├── components/ui/├── lib/└── features/ ├── orders/ ├── inbox/ └── settings/
Arquivos de rota importam apenas de @/features/<nome>
Mantém a navegação desacoplada dos internos da feature
Features importam outras features via seu index.ts
Previne acoplamento por caminhos profundos
Nunca importe components/ de features irmãs diretamente
OrderRow não é um primitivo compartilhado - duplique ou promova para ui/
lib/ e components/ui/ são a camada compartilhada
Utilitários de corte transversal e tokens de design vivem aqui
// ✅ Importação entre features através da API públicaimport type { Order } from "@/features/orders";// ❌ Acessando os internos de outra featureimport { OrderRow } from "@/features/orders/components/OrderRow";
// features/settings/screens/SettingsScreen.tsx - tela de feature usa primitivo compartilhadoimport { Screen } from "@/components/ui/Screen";import { Text } from "react-native";export function SettingsScreen() { return ( <Screen title="Settings"> <Text>Notifications, account, and privacy live here.</Text> </Screen> );}
Mantenha components/ui/ livre de importações de features. Se Screen precisar de dados da feature, passe-os como props - não importe de features/.
Cemitério global de components/ - Cada card de uso único vai para components/ porque "é reutilizável algum dia". Correção: Padrão para features/<nome>/components/; promova para ui/ apenas depois que o segundo consumidor existir.
Arquivos de rota "gordos" em app/ - Lógica de negócios, chamadas de fetch e modais vivem em app/(tabs)/orders/index.tsx. Correção: Re-exporte de features/orders; mantenha rotas com ~5 linhas.
Importações profundas entre features - features/inbox importa features/orders/components/OrderRow. Correção: Importe tipos de @/features/orders; duplique linhas apresentacionais pequenas ou extraia UI compartilhada para components/ui/.
Sem API pública index.ts - Cinquenta arquivos por feature sem limite de exportação; tudo é público. Correção: Exporte apenas telas e tipos compartilhados de index.ts; trate outros caminhos como privados.
Pastas de camada mais pastas de feature - screens/OrdersScreen.tsx e features/orders/screens/OrdersScreen.tsx existem ambos. Correção: Escolha um esquema por app; a confusão híbrida dobra o custo de busca.
Hooks compartilhados na camada errada - useOrders no hooks/ global, mas apenas Pedidos o usa. Correção: Coloque hooks de feature única sob features/orders/hooks/; reserve hooks/ global para comportamento verdadeiramente compartilhado (useAppTheme).
Pacotes Monorepo sem limites de feature - packages/ui compartilhado cresce com props específicas de feature. Correção: Mantenha features de produto no app; pacotes contêm apenas primitivos. Veja Pacotes Compartilhados e Resolução Metro.
Um diretório que contém tudo o que uma área de produto precisa - telas, hooks, componentes, tipos - para que os engenheiros trabalhem em uma única subárvore. Exemplo: src/features/orders/.
O que é uma estrutura em camadas?
Pastas de nível superior agrupadas por função técnica: components/, hooks/, screens/, services/. Cada feature espalha arquivos por essas pastas em vez de uma única fatia.
O que vai em app/ vs features/?
app/ contém arquivos de rota do Expo Router - mapeamento de URL e aninhamento de layout. features/ contém a implementação - telas, hooks e componentes de feature. Arquivos de rota devem re-exportar telas de feature.
O que vai em components/ui/ vs features/*/components/?
components/ui/ - primitivos do sistema de design usados por muitas features (Button, Screen, TextField). features/*/components/ - UI específica do produto usada apenas dentro dessa feature (OrderRow, InboxThread).
Por que usar index.ts em cada feature?
Define a API pública. Outras features e rotas importam @/features/orders - não caminhos profundos. Os internos podem mudar sem quebrar os consumidores.
Features podem importar de outras features?
Sim, mas apenas através do index.ts da outra feature - tipicamente tipos ou uma única tela exportada. Evite importar componentes internos; isso acopla features silenciosamente.
Quando devo usar pastas em camadas em vez disso?
Apps muito pequenos com poucas telas e um único desenvolvedor. Assim que PRs rotineiramente tocam múltiplas pastas de nível superior para uma feature, migre para fatias.
Como migro de camadas para fatias?
Escolha a pior tela "god". Crie features/<nome>/, mova sua tela, hooks e componentes, adicione index.ts e afine o arquivo de rota. Repita por feature - nenhuma reescrita "big-bang" é necessária.
Onde vivem os clientes de API e autenticação?
Infraestrutura de corte transversal em src/lib/ - api.ts, storage.ts, analytics.ts. Hooks de feature chamam lib/; lib/ não importa de features/.
Hooks devem ser globais ou por feature?
Por feature quando apenas uma tela os usa (useOrders em features/orders/hooks/). Global em src/hooks/ quando compartilhado entre features (useAppTheme, useSession).
Armadilha: por que nossa pasta global components/ se tornou incontrolável?
Wrappers de uso único se acumulam porque "components/" parece o lugar certo para qualquer arquivo JSX. Padrão para componentes locais da feature; promova para ui/ apenas com um segundo consumidor real.
Como isso interage com container/presenter?
features/<nome>/screens/ contém containers (dados, navegação). features/<nome>/components/ contém presenters (UI apenas com props). Veja Padrões de Componentes Básicos.
O Expo Router requer features/?
Não - o Router apenas requer um diretório app/. features/ é uma convenção organizacional que mantém as rotas finas e a implementação testável.
Como funcionam aliases de caminho como @/*?
Templates do Expo enviam tsconfig.json com "paths": { "@/*": ["./*"] } ou "./src/*". Aponte @/ para src/ para que @/features/orders resolva consistentemente. O Metro respeita os mesmos caminhos quando configurado via expo/tsconfig ou babel-plugin-module-resolver, se necessário.
E os testes - colocalos ou pasta __tests__?
Coloque OrderRow.test.tsx ao lado de OrderRow.tsx dentro da pasta da feature. Testes de integração de feature vivem em features/orders/__tests__/ se você preferir agrupar. Mantenha os testes dentro da fatia que você está testando.