Если убрать все красивые схемы, круги и названия слоёв, чистая архитектура сводится к одному простому правилу:
Зависимости направлены внутрь.
Звучит максимально просто и понятно, но именно здесь чаще всего возникают проблемы.
📌 Что значит «внутрь»?
Вспомним картинку с изображением основных слоёв в чистой архитектуре:
- Presentation (HTTP, контроллеры)
- Application (use cases)
- Domain (бизнес-логика)
- Infrastructure (БД, ORM, внешние API)
Если зависимости направлены внутрь, то верное направление будет таким:
Presentation → Application → Domain
Infrastructure → Domain
То есть:
- Контроллер знает про use case
- Use case знает про домен
- Инфраструктура знает про домен
- Домен не знает ни про кого
❗ Domain — самый внутренний слой. И он не должен ничего импортировать из внешнего мира.
Почему это так важно?
Как только домен узнаёт про ORM, HTTP или какую-то библиотеку, происходит следующее:
- Бизнес-логика начинает зависеть от конкретной библиотеки
- Замена ORM или любой другой зависимости превращается в миграцию всей системы
- Тестирование без базы становится невозможным
Проще говоря: библиотека начинает управлять вами, а не вы ею.
В своей практике я это прочувствовал несколько раз: когда переезжали с sequelize, избавлялись от request и moment. И это только часть примеров, с которыми я столкнулся, присоединившись к проекту.
Простые примеры для иллюстрации проблемы
😭 Плохо:
import { PrismaClient } from '@prisma/client'
export class UserService {
async register(...) {
const prisma = new PrismaClient()
...
}
}
Здесь доменный сервис стал зависеть от Prisma.
Теперь мы с библиотекой «навечно».
👍 Лучше:
export interface UserRepository {
save(user: User): Promise<void>
}
Домен определяет контракт, а реализация происходит на уровне инфраструктуры.
Домену всё равно, SQLite там, PostgreSQL или вообще in-memory реализация для тестов. В репозитории я как раз привёл пример реализации in-memory варианта.
🧠 Ментальная модель
Представь, что Domain — это отдельная библиотека с бизнес-логикой.
Можно ли её вынести в отдельный npm-пакет без Prisma (или любого другого ORM), без Express, Fastify или axios?
Если да — ты на верном пути к чистой архитектуре.
Если нет — значит что-то не так с зависимостями и стоит ещё раз проверить соблюдение правила.
🎯 Файловая структура вторична
Часто чистую архитектуру демонстрируют, отталкиваясь от файловой структуры. Мол, есть директории domain / application / infrastructure, значит точно в проекте clean architecture.
Но это не показатель.
Если где-то в Domain есть что-то вроде:
import { PrismaClient } from '@prisma/client'
— архитектура уже нарушена.
Запоминаем: Clean Architecture — это не про структуру директорий.
Это про направление зависимостей.
В следующей серии посмотрим, как это выглядит в коде 🧑💻