📬 Originally published on ZenOfCode

I'm reposting here to share with more devs — feedback welcome!

Stop Overengineering: Clean Architecture for Real-World APIs

If you’ve ever opened a codebase and thought “WTF is all this layering?”, you’re not alone. Clean architecture is powerful — but it’s easy to take it too far and turn your API into a slow-motion car crash of abstraction.

In this post, I’ll break down a practical version of clean architecture for building APIs that are clean, scalable, and easy to ship.

⚙️ What is “Clean Architecture”... really?

At its core:

  • Business logic should live in one place

  • External systems (DBs, APIs, UI) are details, not your core

  • Your code should read like the use-case it solves

🧱 Layers That Actually Matter

Here’s a simple structure that works:

/src
  /Application  ← Business logic (use cases, services)
  /Domain       ← Models and rules
  /Infrastructure ← Database, API clients
  /Web          ← Controllers, HTTP handlers

No fluff. No 13 interfaces for a method that sends an email.

🧼 Keep These Rules in Mind

1. Use Interfaces Where You Actually Swap Implementations

If you’re never going to mock or switch your EmailService, don’t create IEmailSenderFactoryAdapterV2. Keep it simple.

2. Your Controllers Should Do Almost Nothing

No logic in the controller. Just call your use case, handle the response.

[HttpPost("users")]
public async Task<IActionResult> CreateUser(CreateUserRequest request)
{
    var result = await _createUserUseCase.Execute(request);
    return Ok(result);
}

3. Dependency Injection is a Tool, Not a Religion

Wire up only what you need. Avoid over-wiring things you’ll never use.

🚀 Real-World Example: Creating a User API

Here’s how a real CreateUser use case might flow:

  • Controller gets the HTTP request

  • Calls CreateUserUseCase from Application

  • CreateUserUseCase validates + handles logic

  • Calls UserRepository (in Infrastructure)

  • Returns a result

Boom. Clean. Easy to test. Easy to maintain.

🧠 TL;DR

  • Don’t overengineer for problems you don’t have

  • Keep things layered — but practical

  • Clean code is readable, not academic

  • Code Zen = Calm Code = Happy Dev 😌


🧘‍♂️ Like this kind of content?

Follow my dev blog → ZenOfCode

Or drop me a follow here on Dev.to 💬