clean-architecture-layers
Garanta a direção das dependências em clean architecture — camadas internas não devem referenciar camadas externas.
Detalhes da regra
Seção intitulada “Detalhes da regra”Clean architecture determina que as dependências apontem para dentro: API → Application → Domain. A camada Domain não deve ter dependências externas, a camada Application não deve referenciar Infrastructure diretamente, e nenhuma camada inferior deve referenciar o projeto API. Esta regra verifica diretivas using (C#) ou declarações import para garantir essas fronteiras.
O mesmo padrão se aplica a qualquer arquitetura em camadas em qualquer linguagem — ajuste os padrões de import e os caminhos das camadas conforme necessário.
Exemplos de código incorreto
Seção intitulada “Exemplos de código incorreto”using Microsoft.EntityFrameworkCore; // ✗ Domain → Infrastructureusing StavangerChallenge.Infrastructure; // ✗ Domain → Infrastructureusing StavangerChallenge.Infrastructure; // ✗ Application → Infrastructureusing StavangerChallenge.API; // ✗ Application → APIExemplos de código correto
Seção intitulada “Exemplos de código correto”namespace StavangerChallenge.Domain.Entities;// No external dependencies — pure domain logicusing StavangerChallenge.Domain.Entities; // ✓ Application → Domain// Uses IRepository<T> interface, not Infrastructure directlyImplementação da regra
Seção intitulada “Implementação da regra”/// <reference path="../rules.d.ts" />
export default { rules: { "no-infrastructure-in-domain": { description: "Domain layer must not reference Infrastructure or ORM packages", async check(ctx) { const domainFiles = await ctx.glob("backend/src/**/Domain/**/*.cs"); for (const file of domainFiles) { const matches = await ctx.grep( file, /using\s+(Microsoft\.EntityFrameworkCore|MyApp\.Infrastructure)/ ); for (const match of matches) { ctx.report.violation({ message: `Domain must not reference Infrastructure: "${match.content.trim()}"`, file: match.file, line: match.line, fix: "Remove this using directive. Domain entities should have zero external dependencies.", }); } } }, }, "no-infrastructure-in-application": { description: "Application layer must not reference Infrastructure directly", async check(ctx) { const appFiles = await ctx.glob("backend/src/**/Application/**/*.cs"); for (const file of appFiles) { const matches = await ctx.grep(file, /using\s+MyApp\.Infrastructure/); for (const match of matches) { ctx.report.violation({ message: `Application must not reference Infrastructure: "${match.content.trim()}"`, file: match.file, line: match.line, fix: "Define an interface in Application and implement it in Infrastructure.", }); } } }, }, "no-upward-api-references": { description: "No layer should reference the API project", async check(ctx) { const lowerLayerPatterns = [ "backend/src/**/Domain/**/*.cs", "backend/src/**/Application/**/*.cs", "backend/src/**/Infrastructure/**/*.cs", ]; for (const pattern of lowerLayerPatterns) { const files = await ctx.glob(pattern); for (const file of files) { const matches = await ctx.grep(file, /using\s+MyApp\.API/); for (const match of matches) { ctx.report.violation({ message: `Lower layers must not reference the API project: "${match.content.trim()}"`, file: match.file, line: match.line, fix: "Dependencies flow inward: API → Application → Domain.", }); } } } }, }, },} satisfies RuleSet;Para projetos TypeScript, adapte os padrões:
// Check that domain/ does not import from infrastructure//import\s+.*from\s+["'].*\/infrastructure\//
// Check that no layer imports from api//import\s+.*from\s+["'].*\/api\//Quando usar
Seção intitulada “Quando usar”Quando seu projeto segue clean architecture, arquitetura hexagonal, ou qualquer arquitetura em camadas onde a direção das dependências precisa ser garantida.
Quando não usar
Seção intitulada “Quando não usar”Quando seu projeto não utiliza uma arquitetura em camadas, ou quando as camadas não estão organizadas em diretórios distintos.