Para um Analista Sênior, a organização de pastas deve refletir não apenas a separação de responsabilidades, mas também facilitar a testabilidade, a substituição de infraestrutura e a descoberta do domínio.
Abaixo, apresento uma estrutura baseada em Clean Architecture e DDD (Domain-Driven Design), que eleva o padrão de camadas simples para algo preparado para escala e desacoplamento.
☕ Estrutura para Java (Maven/Gradle)
No ecossistema Java, utilizamos a estrutura de sub-módulos para garantir que as dependências fluam na direção correta (da infraestrutura para o domínio).
Plaintext
nome-do-projeto/
├── domain/ # Camada de Negócio Pura (Enterprise Rules)
│ ├── model/ # Entidades e Value Objects
│ ├── repository/ # Interfaces (Ports) de Repositório
│ ├── service/ # Serviços de Domínio (Regras complexas)
│ └── exception/ # Exceções de negócio
├── application/ # Casos de Uso (Application Rules)
│ ├── usecase/ # Interfaces/Implementações de fluxos de ação
│ ├── dto/ # Request/Response (Data Transfer Objects)
│ └── mapper/ # Conversores (Entity <-> DTO)
├── infrastructure/ # Implementações Técnicas (Details)
│ ├── persistence/ # Implementação JPA/Hibernate/JDBC
│ │ ├── entity/ # Entidades de Banco (Database Models)
│ │ └── repository/ # Implementação das interfaces do Domain
│ ├── configuration/ # Beans do Spring/Quarkus e segurança
│ ├── client/ # Consumo de APIs externas (Feign, RestTemplate)
│ └── messaging/ # Kafka, RabbitMQ, SQS
└── presentation/ # Ponto de Entrada (Delivery Mechanism)
├── controller/ # REST Controllers
├── advice/ # Exception Handlers globais
└── validation/ # Custom Validators
🔷 Estrutura para C# (.NET)
No .NET, a organização costuma seguir o padrão de múltiplas Libraries (.csproj) dentro de uma Solution (.sln). Isso impede fisicamente que a camada de domínio enxergue o banco de dados, por exemplo.
Plaintext
SolutionName/
├── src/
│ ├── Project.Domain/ # O Coração: Sem dependências externas
│ │ ├── Entities/
│ │ ├── Interfaces/ # IRepository, IUnitOfWork
│ │ ├── ValueObjects/
│ │ └── Exceptions/
│ ├── Project.Application/ # Orquestração (Referencia o Domain)
│ │ ├── Services/ # Application Services
│ │ ├── Models/ # ViewModels ou DTOs
│ │ ├── Mappings/ # Perfis do AutoMapper
│ │ └── Validators/ # FluentValidation
│ ├── Project.Infrastructure/ # Detalhes (Referencia Application e Domain)
│ │ ├── Data/ # DbContext, Migrations
│ │ │ ├── Repositories/ # Implementações EF Core/Dapper
│ │ │ └── Configurations/ # Fluent API (Entity Mapping)
│ │ └── ExternalServices/ # Gateways de Pagamento, Email, Auth
│ └── Project.API/ # Apresentação (Referencia Infra e Application)
│ ├── Controllers/
│ ├── Middlewares/
│ └── Program.cs # Injeção de Dependência (DI Container)
├── tests/
│ ├── Project.UnitTests/
│ └── Project.IntegrationTests/
└── README.md
🧠 Pontos Chave para a Senioridade
Inversão de Dependência (DIP): Observe que a camada de Domínio define a interface do repositório (
IRepository), mas quem a implementa é a Infraestrutura. Isso permite trocar o MySQL pelo PostgreSQL sem tocar em uma linha de regra de negócio.Separação de Modelos: Evite usar a classe anotada com
@Entity(Java) ou as classes do Entity Framework como retorno na sua API. Use DTOs/ViewModels na camada de Apresentação. Isso protege seu contrato de API de mudanças no esquema do banco.Serviços vs. Casos de Uso: Em projetos maiores, a pasta
servicescostuma ficar inflada. Substituir porUseCases(um arquivo por ação, ex:ProcessarPedidoUseCase.java) torna o sistema muito mais fácil de navegar.Descoberta: Ao abrir a pasta
Domain, um novo desenvolvedor deve entender imediatamente do que o sistema se trata (ex:Orders,Payments,Inventory), e não apenas ver pastas genéricas comoModelseControllers.
Qual dessas abordagens você sente que melhor se adapta ao tamanho atual dos seus times?