1. Clean Architecture
What is Clean Architecture?
Clean Architecture is a layered architectural pattern aimed at creating maintainable, testable, and scalable applications. It organizes codebases into concentric layers with clear separation of concerns, where the core business/domain logic is independent of UI, infrastructure, or external dependencies.
Why use Clean Architecture?
- Ensures separation of concerns: business rules are isolated from frameworks and UI.
- Promotes testability and maintainability by decoupling code.
- Allows independent development and evolution of layers.
- Facilitates dependency inversion, where outer layers depend on core abstractions, not implementations.
- Makes it easier to replace or update UI, infrastructure, or data layers without affecting the core.
Typical Layers in Clean Architecture (from innermost to outermost)
Layer | Responsibility |
Domain | Core business logic, entities, value objects, domain events, interfaces. No dependencies on other layers. |
Application | Use cases, business rules orchestration, CQRS commands/queries, service interfaces. Depends on Domain. |
Infrastructure | Implementation of data access, external services, messaging, caching. Depends on Application and Domain. |
Presentation | UI, API controllers, UI-specific logic. Depends on Application for use cases. |
Example Folder/Project Structure in .NET
MySolution/ |-- MyApp.Domain/ # Entities, value objects, domain events |-- MyApp.Application/ # Use cases, commands, queries, interfaces |-- MyApp.Infrastructure/ # EF Core, repositories, data access implementation |-- MyApp.API/ # ASP.NET Core Web API project with controllers |-- MyApp.Tests/ # Unit and integration tests per layer
- The Domain does not reference any other projects.
- The Application references Domain only.
- The Infrastructure references Application and Domain.
- The API references Application and Infrastructure at runtime but ideally compiles against Application only for core logic.
How to implement in .NET?
- Use class library projects for layers (Domain, Application, Infrastructure).
- Use dependency injection to provide infrastructure implementations to application services.
- Implement repositories and external service integrations in Infrastructure.
- Use MediatR for CQRS pattern in Application layer for commands and queries.
- Controllers in API layer act as user input handlers invoking Application layer.
2. Vertical Slice Architecture
What is Vertical Slice Architecture?
Vertical Slice Architecture organizes the codebase around features or use cases rather than technical layers. Each "slice" or feature contains everything needed end-to-end to handle that feature: UI, validation, business logic, data access, etc.
Why use Vertical Slice?
- Promotes feature-first modularity, making the codebase more understandable and maintainable.
- Reduces indecision about where code belongs in traditional layered architecture.
- Facilitates isolated development and testing of features.
- Fits well with CQRS since each command and query can be a vertical slice.
- Improves scalability and refactoring by grouping related logic together.
Typical Structure of a Vertical Slice
For example, in a single vertical slice "CreateOrder":
Slices/ |-- CreateOrder/ |-- Command.cs # Command definition |-- CommandHandler.cs # Command handler business logic |-- Validator.cs # Validation rules |-- DTOs.cs # Data Transfer Objects |-- MappingProfile.cs # AutoMapper configuration if needed
At the root or in a top-level folder, you can organize many vertical slices side by side.
Combining Vertical Slice with Clean Architecture
- Keep Domain and Infrastructure layers as independent layers.
- Combine Application and Presentation layers by slicing features vertically.
- This means each feature folder contains handlers, commands, queries, validators, and sometimes API endpoints.
Example folder structure combining Vertical Slice into Clean Architecture:
MySolution/ |-- Domain/ |-- Infrastructure/ |-- Features/ |-- FeatureA/ |-- Commands/ |-- Queries/ |-- Handlers/ |-- FeatureB/ |-- API/ (or Presentation Layer)
3. Modular Monolith
What is Modular Monolith?
A Modular Monolith is a monolithic application that is carefully modularized into well-defined modules that encapsulate functionality and enforce boundaries internally, as opposed to splitting into distributed microservices.
Why use Modular Monolith?
- Avoids the complexity and operational overhead of microservices while maintaining modularity.
- Easier to deploy, test, and debug than distributed systems.
- Modules can be independently developed, tested, and understood.
- Encourages strong boundaries and encapsulation within the monolith.
- Provides a stepping stone architecture for future microservices splitting.
Typical Modular Monolith Structure
- Application divided into modules by business capabilities.
- Each module encapsulates domain, application services, and infrastructure relevant to that module.
- Communication between modules can be event-driven or via interfaces.
- Modules communicate through shared contracts and abstractions only.
Example folder structure:
MyMonolith/ |-- Modules/ |-- Sales/ |-- Domain/ |-- Application/ |-- Infrastructure/ |-- Inventory/ |-- Billing/ |-- SharedKernel/ # Common utilities and base classes |-- API/
How to implement Modular Monolith in .NET?
- Use .NET class libraries per module.
- Define clear module boundaries and expose only necessary interfaces.
- Use Dependency Injection to wire modules together.
- Optionally use events or a mediator pattern for inter-module communication.
- Design for high cohesion and low coupling between modules.
Summary Comparison
Aspect | Clean Architecture | Vertical Slice | Modular Monolith |
Focus | Layered separation of concerns | Feature/use-case based organization | Modular, well-encapsulated monolith |
Structure | Domain, Application, Infrastructure, Presentation layered projects | Feature folders with end-to-end code | Modules with domain, app, infra per module |
Advantages | Testability, maintainability, scalability | Feature isolation, easier to navigate | Balance between monolith simplicity and modularity |
Typical Usage | Medium to large applications with complex domain logic | Any size; great with CQRS and MediatR | Large monoliths aiming for modular design |
Dotnet Implementation | Separate library projects per layer | Folders or projects per feature slices | Library projects per module with clear boundaries |
References
- Clean Architecture in .NET: Code Maze
- Clean Architecture Folder Structure Guide: Milan Jovanovic Blog
- Combining Clean Architecture and Vertical Slice: Anton Dev Tips
- Modular Monolith Concepts: Microsoft Docs & community blogs (search for modular monolith in .NET architecture)