dare-layered-design
Enforce arquitetura estrita de 4 camadas (Handlers, Services, Repositories, Models) em todos os projetos DARE, independente de linguagem ou framework. Inspirado em "Layered Design for Ruby on Rails Applications" de Vladimir Dementyev (Evil Martians).
- License 许可
- Apache-2.0
- 最近更新
- 2026-10-23
- Stars
- ★ 0
- Forks
- 0
01 前言 Front Matter
- name
- dare-layered-design
- description
- Enforce arquitetura estrita de 4 camadas (Handlers, Services, Repositories, Models) em todos os projetos DARE, independente de linguagem ou framework. Inspirado em "Layered Design for Ruby on Rails Applications" de Vladimir Dementyev (Evil Martians).
03 SKILL.md 正文
DARE Layered Design Skill
Você é um especialista em arquitetura de software e Layered Design. Seu papel é garantir que todo projeto DARE — independente da stack — siga estritamente o pipeline Handler → Service → Repository → Model, sem atalhos.
Quando usar esta skill
- Você está revisando um Pull Request e quer verificar se as camadas foram respeitadas
- Você está gerando código de scaffold (CRUD, novo módulo, novo endpoint)
- Você está auditando um projeto legado que vai começar a usar DARE
- Você está em
/dare-blueprintdecidindo a estrutura de pastas
As 4 camadas (regra única, sem exceção)
┌──────────────────────────────────────────┐
│ Handler (HTTP, gRPC, CLI, queue worker) │ ← entrada
└──────────────────────────────────────────┘
↓
┌──────────────────────────────────────────┐
│ Service (lógica de negócio, 1 operação) │ ← coração
└──────────────────────────────────────────┘
↓
┌──────────────────────────────────────────┐
│ Repository (acesso a dados, abstração) │ ← I/O
└──────────────────────────────────────────┘
↓
┌──────────────────────────────────────────┐
│ Model (entidade pura, sem HTTP/DB) │ ← domínio
└──────────────────────────────────────────┘
Handlers (controllers, routers, routes)
Responsabilidades
- Receber request HTTP/gRPC/CLI
- Validar input (delegar para FormRequest/Pydantic/Zod/serde)
- Chamar um service
- Retornar response formatada
NUNCA
- Acessar Repository diretamente
- Conter lógica de negócio
- Fazer query em banco
- Instanciar Service com
new(use injeção)
Services (use_cases, interactors, commands)
Responsabilidades
- Implementar uma operação de negócio (
RegisterUser,RefundPayment) - Orquestrar Repositories
- Validar regras de negócio
- Lançar exceções de domínio (
UserAlreadyExists,InsufficientFunds)
NUNCA
- Saber sobre HTTP (status code, headers)
- Saber sobre framework web
- Conter SQL inline (usa Repository)
Repositories (repos, data_access, stores)
Responsabilidades
- Abstrair persistência (Postgres, Redis, S3, Stripe API)
- Retornar Models ou primitivos
- Esconder detalhes de SQL/HTTP externo
NUNCA
- Retornar HTTP status code
- Lançar exceções de domínio (retorna
Option<Model>ounull) - Conter regra de negócio
Models (entities, domain, structs)
Responsabilidades
- Representar entidade do domínio
- Conter invariantes (
Emailválido,Moneypositivo)
NUNCA
- Conter referência a HTTP, DB, framework
- Importar de Repository/Service/Handler
Métricas obrigatórias
| ID | Métrica | Como medir |
|---|---|---|
| M-01 | 100% dos Services têm testes unitários (sem DB/HTTP real) | linter checa tests/services/* |
| M-02 | 0% de chamadas Handler→Repository diretas | linter AST/grep |
| M-03 | 100% dos Handlers usam injeção (sem new Service() inline) |
linter AST/grep |
| M-04 | 100% dos Repositories são agnósticos das camadas superiores (não retornam HTTP status) | linter |
Tabela tradução por linguagem
| Camada DARE | Laravel | NestJS | FastAPI | Rails | Rust/Axum | Go/Gin |
|---|---|---|---|---|---|---|
| Handler | Http/Controllers/ |
*.controller.ts |
routers/*.py |
app/controllers/ |
handlers/*.rs |
handlers/*.go |
| Service | Services/ |
*.service.ts |
services/*.py |
app/services/ |
services/*.rs |
services/*.go |
| Repository | Repositories/ |
*.repository.ts |
repositories/*.py |
app/repositories/ |
repositories/*.rs |
repositories/*.go |
| Model | Models/ |
entities/*.ts |
models/*.py |
app/models/ |
domain/*.rs |
models/*.go |
Antipatterns
| AP | Antipattern | Sinal | Correção |
|---|---|---|---|
| AP-01 | Handler chama Repository | controller.repo.find() |
Criar Service entre eles |
| AP-02 | Service faz SQL inline | db.query("SELECT...") em Service |
Mover para Repository |
| AP-03 | Repository lança exceção de domínio | throw UserNotFound em Repo |
Retornar null/Option/Maybe |
| AP-04 | Model importa Service | Model.payment_service |
Refatorar: Service usa Model, não o contrário |
| AP-05 | God Service (tudo em uma classe) | UserService com 30 métodos |
Quebrar em RegisterUser, ResetPassword, ... |
| AP-06 | Fat Controller | Controller > 100 linhas | Mover lógica para Service |
Como aplicar na prática
Passo 1: Identificar as camadas no projeto
Mapear pastas existentes para as 4 camadas. Se faltarem (ex: projeto Laravel só com Controllers + Models), planejar refactor incremental.
Passo 2: Adicionar lint
Use ESLint plugin custom, Rubocop cop custom, clippy lint custom, ou apenas grep em CI:
# Detecta Handler→Repository direto
grep -rn "import.*Repository" src/controllers/ && exit 1
Passo 3: Cobrir Services com testes unitários
Service NÃO depende de DB nem HTTP real — usa Repository mockado. Suite roda em milissegundos.
// Exemplo NestJS
describe('RegisterUserService', () => {
it('falha se email já existe', async () => {
const repo = { findByEmail: jest.fn().mockResolvedValue({id: 1}) };
const sut = new RegisterUserService(repo as any);
await expect(sut.execute({email: 'x@y.com'})).rejects.toThrow('email exists');
});
});
Passo 4: Validar com Ralph Loop
A cada task:
npm test/cargo test/pytest— Services 100% verdenpm run lint— sem AP-01 a AP-06
Boas práticas
- Uma operação = um Service — facilita teste, reuso e nomeação
- Repository devolve Model, não DTO — DTO é responsabilidade do Handler/Presenter
- Models são imutáveis quando possível — mudanças passam por Service
- Presenter como 5ª camada opcional — converte Model → JSON/XML
Dicas para melhor resultado
- Leia
docs/design/skills/dare-layered-design/DESIGN.mdpara o "porquê" e exemplos detalhados - Combine com
dare-feature-designao adicionar feature em código legado — siga as 4 camadas mesmo se o legado não seguir - Templates de scaffold estão em
packages/skills/dare-layered-design/por linguagem
Esta skill é parte do DARE Method e está sob licença MIT.
04 同仓库更多 Skills
commands
暂无简介
commands
暂无简介
skill-rails-api
Padrões DARE para APIs em Ruby on Rails 8 — API mode, ActiveRecord, Solid Queue, Solid Cable, Action Cable, strong parameters, services (interactors), serializers (Blueprinter/Alba), Devise/JWT, rack-attack, rswag/grape-swagger.
skill-nestjs-api
Padrões DARE para APIs REST em NestJS + TypeScript + Prisma + Swagger. Modules, Controllers, Services, DTOs com class-validator, Guards, Interceptors, exceções globais, Jest + Supertest, OpenAPI auto-gerado, rate limiting com @nestjs/throttler.
skill-mcp-server
Padrões DARE para servidores MCP (Model Context Protocol) em TypeScript ou Python. Define tools, resources, prompts; suporta transports stdio, SSE e HTTP; validação Zod/Pydantic; autorização por tool; tracing estruturado; testes; publicação no MCP registry.
skill-go-gin-api
Padrões DARE para APIs REST em Go + Gin (ou stdlib net/http) + sqlc + PostgreSQL. Handlers, services, repositories, middleware, validação com go-playground/validator, JWT, rate limit, swag (OpenAPI), testes com testify e httptest.