Clean Architecture Principles for Backend Applications

Clean Architecture (and similar patterns like Hexagonal/Ports-and-Adapters architecture) organizes code so business logic doesn’t depend on frameworks, databases, or UI details — a genuinely valuable discipline once an application outgrows a simple CRUD script.

# Business logic (the "core") knows NOTHING about the database or web framework
class OrderService:
    def __init__(self, order_repository, payment_gateway):
        self.orders = order_repository   # an INTERFACE, not a concrete database class
        self.payments = payment_gateway   # same - an interface

    def place_order(self, items, customer_id):
        total = sum(item.price for item in items)
        if not self.payments.charge(customer_id, total):
            raise PaymentFailedError()
        return self.orders.save(Order(items, customer_id, total))

# Concrete implementations live at the OUTER layer, plugged in via dependency injection
class PostgresOrderRepository:
    def save(self, order): ...  # actual SQL here

class StripePaymentGateway:
    def charge(self, customer_id, amount): ...  # actual Stripe API calls here

Why This Separation Matters

OrderService can be tested completely without a real database or payment provider — just pass in fake/mock implementations of the interfaces. It can also be unit-tested in milliseconds rather than requiring a real database connection, and swapping Stripe for a different payment provider later touches only the outer layer, never the core business logic.