Мартин чистая архитектура
Мартин чистая архитектура — это не просто модный термин из мира разработки ПО, а фундаментальный подход к проектированию систем, который позволяет создавать гибкие, тестируемые и легко поддерживаемые приложения независимо от технологий, фреймворков или интерфейсов. В эпоху быстрой смены инструментов и платформ, когда бэкенд-фреймворк может устареть за два года, а фронтенд-библиотека — за шесть месяцев, чистая архитектура даёт устойчивость: она отделяет бизнес-логику от деталей реализации, делая код не привязанным к внешним зависимостям. Это особенно критично для корпоративных систем, стартапов, ожидающих масштабирования, и любых проектов, где срок жизни превышает 1–2 года.
- Что такое чистая архитектура по Мартину?
- Основные принципы чистой архитектуры
- Слои и направление зависимостей
- Сущности и юз-кейсы: ядро системы
- Интерфейсы и адаптеры: связь с внешним миром
- Практический пример: реализация на TypeScript
- Частые ошибки и как их избежать
- Экспертное мнение: когда чистая архитектура оправдана
- Вопросы и ответы
- Заключение
Что такое чистая архитектура по Мартину?
Чистая архитектура (Clean Architecture) — это концепция, предложенная Робертом С. Мартином (Robert C. Martin), известным как «Боб Мартин», автором книг «Чистый код» и «Принципы, шаблоны и практики Agile». Она не является конкретным фреймворком или библиотекой, а представляет собой набор принципов проектирования, направленных на разделение ответственности и минимизацию взаимозависимостей между компонентами системы.
В отличие от традиционной многоуровневой архитектуры, где слои (UI → сервисы → репозитории → БД) зависят друг от друга сверху вниз, чистая архитектура строится по принципу «внутри-наружу». Бизнес-логика — ядро системы — не знает ничего о внешних мирах: базах данных, веб-фреймворках, API или пользовательских интерфейсах. Всё, что находится вне ядра, зависит от него, а не наоборот.
Это позволяет легко менять технологии без переписывания бизнес-правил. Например, если вы решите заменить PostgreSQL на MongoDB, или перейти с REST на GraphQL — достаточно изменить адаптеры. Сама логика приложения останется неизменной. Такой подход особенно ценен в условиях неопределённости: стартапы часто меняют технологии, а корпоративные проекты требуют долгосрочной поддержки.
Основные принципы чистой архитектуры
Чистая архитектура опирается на пять ключевых принципов, которые вместе образуют устойчивую основу для любого программного продукта.
Первый — принцип единственной ответственности (Single Responsibility Principle, SRP). Каждый модуль должен отвечать только за одну вещь: например, один класс — только за валидацию заказа, другой — за сохранение в БД.
Второй — принцип инверсии зависимостей (Dependency Inversion Principle, DIP). Высокоуровневые модули не должны зависеть от низкоуровневых. Оба должны зависеть от абстракций. Абстракции не должны зависеть от деталей — детали зависят от абстракций. Именно этот принцип обеспечивает развязку между ядром и внешними системами.
Третий — принцип открытости/закрытости (Open/Closed Principle, OCP). Компоненты должны быть открыты для расширения, но закрыты для модификации. Это позволяет добавлять новые функции, не ломая существующий код.
Четвёртый — принцип разделения интерфейса (Interface Segregation Principle, ISP). Не следует заставлять клиентов зависеть от интерфейсов, которые они не используют. Это приводит к созданию мелких, специализированных интерфейсов вместо монолитных.
Пятый — принцип стабильных зависимостей. Зависимости должны идти в сторону большей стабильности. Бизнес-логика — самая стабильная часть. Поэтому она должна быть в центре, а внешние компоненты — вокруг неё.
Эти принципы не новы — они взяты из SOLID, но в чистой архитектуре они применяются в системном, а не локальном контексте. Это не просто хорошие практики — это архитектурная философия.
Слои и направление зависимостей
Архитектура по Мартину визуализируется как несколько концентрических кругов, где каждый слой имеет строго определённую роль и направление зависимостей.
В центре — сущности (Entities). Это бизнес-объекты, которые содержат правила и данные, не зависящие от внешнего мира. Например, класс `User` с методами `activate()`, `changeEmail()` — без привязки к базе данных или HTTP.
Второй слой — юз-кейсы (Use Cases). Здесь находится бизнес-логика приложения: что система должна делать. Юз-кейсы — это классы, которые координируют действия сущностей, вызывают репозитории, обрабатывают ошибки. Они не знают, откуда пришёл запрос — из веба, мобильного приложения или API. Они просто получают данные и возвращают результат.
Третий слой — интерфейсы адаптеров (Interface Adapters). Это мост между ядром и внешним миром. Здесь находятся контроллеры, презентеры, мапперы, сериализаторы. Например, REST-контроллер в Spring Boot или Express-роутер — это адаптер, который преобразует HTTP-запрос в вызов юз-кейса.
На периферии — фреймворки и инструменты (Frameworks & Drivers). Базы данных, веб-фреймворки, внешние API, очереди сообщений. Это всё, что может меняться без влияния на ядро.
Ключевой момент: зависимости всегда идут внутрь. Сущности не знают о юз-кейсах? Нет — юз-кейсы зависят от сущностей. Юз-кейсы не знают о репозиториях? Нет — они зависят от интерфейсов репозиториев. Адаптеры зависят от юз-кейсов. Фреймворки зависят от адаптеров.
Такое построение гарантирует, что изменение технологии (например, замена Hibernate на JPA) затронет только один слой — адаптеры. Ни один класс бизнес-логики не будет затронут.
Слой |
Ответственность |
Зависит от |
Зависимости от него |
|---|---|---|---|
Сущности (Entities) |
Бизнес-данные и правила |
Нет |
Юз-кейсы |
Юз-кейсы (Use Cases) |
Бизнес-логика, оркестрация |
Сущности |
Адаптеры |
Адаптеры (Adapters) |
Преобразование форматов, интеграция |
Юз-кейсы |
Фреймворки |
Фреймворки и драйверы (Frameworks & Drivers) |
Техническая реализация |
Адаптеры |
Нет |
Сущности и юз-кейсы: ядро системы
Сущности — это сердце чистой архитектуры. Они представляют собой доменные объекты, которые не зависят ни от баз данных, ни от фреймворков. Например, если вы пишете систему управления библиотекой, то сущность `Book` будет содержать методы `checkOut()`, `return()`, `isOverdue()` — и всё. Никаких `@Entity`, `@Table`, `@Column` — только чистый JavaScript/TypeScript/Java-класс с логикой.
Юз-кейсы — это операции, которые можно выполнить над сущностями. Они не являются сервисами в традиционном понимании. Юз-кейс — это класс, который получает входные данные, вызывает сущности, использует репозитории (через интерфейс) и возвращает результат. Он не знает, кто его вызвал: веб-интерфейс, мобильное приложение или cron-задача.
Вот пример юз-кейса на TypeScript:
«`typescript
class BorrowBookUseCase {
constructor(private repository: BookRepository) {}
async execute(input: BorrowInput): Promise {
const book = await this.repository.findById(input.bookId);
if (!book || book.isBorrowed()) {
throw new Error(‘Книга недоступна’);
}
book.borrow(input.borrowerId);
await this.repository.save(book);
return { success: true, dueDate: book.getDueDate() };
}
}
«`
Здесь нет ни HTTP, ни SQL, ни ORM. Только бизнес-логика. Это делает юз-кейс идеально тестируемым: вы можете протестировать его без запуска сервера, базы данных или API.
Представьте, что вы внедряете новую функцию: «Автоматическое продление брони при оплате». Вы не трогаете сущности — они не знают про оплату. Вы создаёте новый юз-кейс `ExtendBorrowingOnPaymentUseCase`, который использует существующие сущности и репозитории. Всё — без рефакторинга ядра.
Интерфейсы и адаптеры: связь с внешним миром
Адаптеры — это мост между чистым ядром и внешними технологиями. Они реализуют интерфейсы, объявленные в слое юз-кейсов. Это ключевая идея: юз-кейс говорит: «Мне нужен репозиторий», но не знает, как он реализован. Адаптер говорит: «Вот реализация репозитория через PostgreSQL».
Интерфейс репозитория (объявлен в слое юз-кейсов):
«`typescript
interface BookRepository {
findById(id: string): Promise;
save(book: Book): Promise;
}
«`
Реализация адаптера (в слое фреймворков):
«`typescript
class PostgreSQLBookRepository implements BookRepository {
async findById(id: string): Promise {
const result = await db.query(‘SELECT * FROM books WHERE id = $1’, [id]);
return result.rows[0] ? mapToEntity(result.rows[0]) : null;
}
async save(book: Book): Promise {
await db.query(
‘UPDATE books SET title = $1, borrowed = $2 WHERE id = $3’,
[book.title, book.isBorrowed(), book.id]
);
}
}
«`
Такой подход позволяет легко заменить PostgreSQL на MongoDB, Firebase или даже файловую систему — достаточно написать новый адаптер, реализующий тот же интерфейс. Юз-кейс при этом не изменится.
Аналогично работают контроллеры: REST-контроллер принимает JSON, преобразует его в входные данные юз-кейса, вызывает его и возвращает ответ в нужном формате. Он не содержит бизнес-логики — только трансляцию.
Это также позволяет легко писать юнит-тесты. Вы можете заменить реальный репозиторий на мок-объект, который возвращает фиксированные данные — и тестировать юз-кейс без подключения к базе.
Практический пример: реализация на TypeScript
Представьте, что вы создаёте сервис для управления задачами (аналог Todo-list). Вы хотите, чтобы система была независимой от фреймворка и легко тестируемой.
Сущность:
«`typescript
class Task {
constructor(
public id: string,
public title: string,
public completed: boolean = false,
public createdAt: Date
) {}
complete(): void {
this.completed = true;
}
uncomplete(): void {
this.completed = false;
}
}
«`
Интерфейс репозитория (в слое юз-кейсов):
«`typescript
interface TaskRepository {
findById(id: string): Promise;
save(task: Task): Promise;
findAll(): Promise;
}
«`
Юз-кейс:
«`typescript
class CompleteTaskUseCase {
constructor(private repository: TaskRepository) {}
async execute(input: { taskId: string }): Promise {
const task = await this.repository.findById(input.taskId);
if (!task) throw new Error(‘Задача не найдена’);
task.complete();
await this.repository.save(task);
}
}
«`
Адаптер (REST-контроллер в Express):
«`typescript
app.put(‘/tasks/:id/complete’, async (req, res) => {
try {
const useCase = new CompleteTaskUseCase(postgreSQLTaskRepository);
await useCase.execute({ taskId: req.params.id });
res.status(200).send({ success: true });
} catch (error) {
res.status(400).send({ error: error.message });
}
});
«`
Теперь вы можете написать тест для `CompleteTaskUseCase`, не запуская сервер:
«`typescript
test(‘should complete task’, async () => {
const mockRepo = {
findById: jest.fn().mockResolvedValue(new Task(‘1’, ‘Test’, false, new Date())),
save: jest.fn()
};
const useCase = new CompleteTaskUseCase(mockRepo as any);
await useCase.execute({ taskId: ‘1’ });
expect(mockRepo.findById).toHaveBeenCalledWith(‘1’);
expect(mockRepo.save).toHaveBeenCalled();
});
«`
Это — чистая архитектура в действии.
Частые ошибки и как их избежать
Даже опытные разработчики допускают типичные ошибки при внедрении чистой архитектуры. Вот основные из них:
- Смешивание слоёв: Контроллеры, содержащие бизнес-логику. Например, `if (user.age > 18)` прямо в роутере. Это ломает принцип инверсии зависимостей. Решение: перенесите логику в юз-кейс.
- Игнорирование интерфейсов: Прямая зависимость от конкретной реализации (например, `new PostgreSQLRepository()` внутри юз-кейса). Это делает систему негибкой. Решение: всегда используйте DI и абстракции.
- Слишком много абстракций: Создание интерфейсов для каждой мелкой сущности. Это ведёт к избыточному коду и усложняет понимание. Решение: интерфейсы нужны только там, где возможна замена реализации.
- Не тестирование юз-кейсов: Тестируются только контроллеры или UI. Это даёт ложное ощущение покрытия. Решение: 80% юнит-тестов должны покрывать юз-кейсы и сущности.
- Использование ORM-аннотаций в сущностях: `@Entity`, `@Column` — это уже зависимость от фреймворка. Решение: сущности должны быть чистыми POJO. ORM-маппинг — задача адаптеров.
Экспертное мнение: когда чистая архитектура оправдана
Чистая архитектура не нужна для MVP с одним разработчиком и сроком 3 месяца. Но она критична, когда:
— Система живёт больше 12–18 месяцев;
— Планируется масштабирование на несколько команд;
— Возможна смена технологий (например, переход с monolith на микросервисы);
— Есть высокие требования к надёжности и тестированию (финансы, здравоохранение, госуслуги).
Для таких проектов чистая архитектура — это не роскошь, а необходимость. Она снижает стоимость поддержки на 30–50% в долгосрочной перспективе (по данным Gartner, 2024). Стоимость изменения бизнес-логики в системе с плохой архитектурой может достигать 70% от стоимости нового функционала.
Совет: начинайте с простого. Не пытайтесь сразу применить все слои. Начните с выделения сущностей и юз-кейсов — даже в существующем проекте. Постепенно рефакторите адаптеры. Чистая архитектура — это не проект, а культура.
Вопросы и ответы
Заключение
Чистая архитектура по Мартину — это не догма, а инструмент для управления сложностью. Она не гарантирует, что ваш код будет идеальным, но она даёт структуру, которая делает его устойчивым к изменениям. Когда технологии меняются, когда требования эволюционируют, когда команды растут — именно чистая архитектура становится тем фундаментом, на котором можно строить, а не перестраивать.
Её сила — в простоте. Вы не пишете больше кода. Вы пишете его правильно: разделяете то, что меняется, от того, что остаётся. Вы создаёте систему, которая не боится будущего.
- Бизнес-логика должна быть независима от фреймворков, БД и UI.
- Зависимости всегда идут внутрь — от внешнего к ядру, а не наоборот.
- Используйте интерфейсы для абстракции внешних зависимостей.
- Тестируйте юз-кейсы и сущности как можно чаще — это ваша главная ценность.
- Не применяйте чистую архитектуру ради неё самой — применяйте, когда система растёт и требует долгосрочной поддержки.
⚠️ Дисклеймер — нажмите, чтобы развернуть
Материалы, опубликованные в разделе «Блог» на сайте RU DESIGN SHOP (rudesignshop.ru), носят исключительно информационный и ознакомительный характер и не являются руководством к действию, финансовой рекомендацией, медицинской услугой, ветеринарным назначением либо рекламой товаров и услуг, включая азартные игры. Публикации не содержат призывов к участию в азартных играх и не направлены на продвижение соответствующих операторов.
Безопасность применения товаров и веществ: при использовании строительных материалов, бытовой химии, пестицидов и агрохимикатов необходимо строго следовать инструкциям производителя и действующему законодательству Российской Федерации, включая Федеральный закон РФ от 19.07.1997 № 109-ФЗ «О безопасном обращении с пестицидами и агрохимикатами».
Упоминание товарных знаков, брендов и организаций носит исключительно информационный характер и не означает наличие партнёрских отношений или одобрения со стороны правообладателей.
Материалы, содержащие сведения о медицинских, ветеринарных или косметических средствах, представлены в справочных целях и не являются медицинской консультацией или назначением. Перед применением рекомендуется обратиться к врачу, ветеринарному специалисту или иному сертифицированному профессионалу.
Возрастные ограничения: материалы, содержащие сведения о продукции категории 18+, включая алкоголь или азартные игры, предназначены исключительно для совершеннолетней аудитории и публикуются в информационных целях.
Правовая ответственность: решения, принятые на основе опубликованной информации, пользователь принимает самостоятельно и на свой риск; редакция и авторы несут ответственность в пределах, установленных законодательством Российской Федерации.
Редакция не допускает публикаций, содержащих пропаганду экстремизма, терроризма, наркотических средств или суицида; подобные материалы подлежат немедленному удалению.
Упоминание организаций с ограниченным статусом: компания Meta Platforms Inc. (социальные сети Facebook и Instagram) признана экстремистской организацией решением суда РФ, её деятельность запрещена на территории Российской Федерации; любые упоминания приводятся исключительно в информационных целях.
Авторские права и источники: информация собирается из открытых источников; её актуальность указывается на дату публикации и может изменяться.
Изображения и иллюстрации используются на условиях, разрешённых правообладателями. При возникновении претензий редакция готова оперативно рассмотреть обращение и внести необходимые изменения.
Персональные данные и cookies: сайт использует cookies и обрабатывает персональные данные пользователей в соответствии с Федеральным законом № 152-ФЗ «О персональных данных» и Политикой конфиденциальности RU DESIGN SHOP.
Мнения авторов могут не совпадать с позицией государственных органов или коммерческих организаций, упомянутых в материалах.