Luis Soares
← Back to articles
ArchitectureJul 10, 2026·12 min

Clean Architecture in .NET without overengineering

Separating domain from infrastructure doesn’t mean ten layers. A pragmatic guide for .NET 9.

LS
Luis Soares
Software architect — .NET · Azure · AI
[ cover image · clean architecture ]

Clean Architecture became shorthand for too many folders and abstractions nobody reads. The original goal is simple: protect business rules from the details that change — database, framework, protocol. Everything beyond that is optional.

The real problem

When business logic lives inside the controller or the DbContext, every infrastructure change becomes risky surgery. The coupling doesn’t show up in the pull request — it shows up six months later, when switching providers costs a whole sprint.

csharp
// pure domain — zero framework references
public sealed class Order
{
    private readonly List<Line> _lines = [];
    public OrderId Id { get; }
    public Money Total => _lines.Sum(l => l.Price);

    public static Result<Order> Create(Cart cart) =>
        cart.IsEmpty
            ? Error.Validation("cart.empty")
            : new Order(cart.Lines);
}

The three layers that matter

In practice you need three clear boundaries — not ten. Domain at the center, application orchestrating use cases, and infrastructure at the edge implementing the interfaces the application declares.

  • Domain — entities and business rules. Zero external dependencies.
  • Application — use cases that depend on interfaces, never on implementations.
  • Infrastructure — EF Core, HTTP, queues. Implements what the application asks for.

The dependency rule is the only non-negotiable one: inner code never knows about the outer.

csharp
public sealed class PlaceOrder(IOrderRepository repo, IClock clock)
{
    public async Task<Result<OrderId>> Handle(Cart cart, CancellationToken ct)
    {
        var order = Order.Create(cart);
        if (order.IsFailure) return order.Error;

        await repo.SaveAsync(order.Value, ct);
        return order.Value.Id;
    }
}

When not to use it

An internal CRUD, a script, a weekend MVP — none of them need layers. They cost navigation and ceremony. Adopt the separation when business rules become valuable enough to outlive the framework you use today.

Start with a straight line and bend it when the pain shows up. Architecture is a response to pressure, not decoration.

LS

Written by Luis Soares — software architect, on the road to Microsoft MVP.