SOLID на собеседовании чаще просят как алфавит: пять букв, определение из учебника, тишина, когда спрашивают «где это у вас в сервисе». Чистую архитектуру рисуют кругами и забывают, что в команде из четырёх человек пять слоёв на CRUD заказа — дороже, чем один понятный модуль.
Ниже — зачем принципы вообще, как звучат без культа, два разбора «до и после» и где они вредят. Это не конспект Роберта Мартина и не замена книге. Если в резюме у вас в шапке «SOLID, DRY, чистый код» без сервиса — сначала уберите это: резюме Java и как описать опыт.
Коротко:
- Пять букв — про стоимость изменений, не про красоту классов.
- Чистая архитектура в быту: правила домена не знают, что внизу Postgres и FastAPI.
- Слепое следование плодит слои «на будущее» не хуже, чем комбайн на 800 строк.
- На интервью просят пример из вашего кода. Определение из карточки не считается.
- В CV нужна поставка, не список аббревиатур. Аббревиатуры оставьте на созвон.
Зачем это, если фича и так работает
Код пишут один раз и меняют десятки. Боль — не написать расчёт скидки, а через полгода вставить новый канал оплаты, не сломав письмо клиенту и отчёт в 1С. Принципы дешевят это: меньше мест, куда протекает одно изменение.
Они не про эстетику репозитория. Репозиторий с десятью интерфейсами на одну реализацию читается хуже комбайна, если никто вторую реализацию не писал и не напишет. Инструмент, не религия. Оверинжиниринг на прототипе — тот же долг, только с умным лицом.
Пять букв без учебника
S — одна причина менять модуль. Класс, который считает сумму заказа, ходит в платёжку и сам шлёт письмо, ломается трижды: сменили шаблон письма — трогаете оплату. Признак: в описании класса три «и».
O — новое поведение без правки старого ствола. Гигантская лестница «если карта / если PayPal / если счёт» в одном методе требует правки при каждом новом способе. Общий договор «способ оплаты» и новый класс рядом дешевле, когда способов реально больше двух и они живут.
L — наследник не подкладывает сюрприз. Квадрат, который ломает «поставил ширину — высота та же», в коде с прямоугольниками даёт баги вёрстки и отчётов. На практике чаще: «заглушка хранилища», которая молча глотает запись, тогда как боевая база кидает ошибку. Тесты зелёные, прод нет. Другой частый сюрприз: кэш, который реализует тот же договор, что база, но при записи «успех» не виден следующему чтению в том же запросе. Подставили кэш в тест — зелень. В проде пользователь видит старую корзину.
I — узкий договор, не комбайн методов. Интерфейс «работник» с code() и cook() заставляет сервис заказов притворяться кухней. Разрежьте. Не делайте десять интерфейсов из одного метода «на чистоту».
D — зависеть от роли, не от Postgres в импорте. Сервис presale не должен знать драйвер. Тогда тест не поднимает базу, а замена Redis на диск — смена одной склейки. Это же идея, которую на схемах называют чистой архитектурой, только на уровне класса.
Пример 1. Заказ, оплата, письмо в одном комбайне
Типичный учебный и, увы, прод-сервис: метод process(order, payment_type). Считает сумму. Внутри ветки карты и PayPal. В конце send_email. Тест либо нет, либо он ходит в почту.
До. Один класс, три ответственности. Новый «оплата при получении» — ещё один elif в том же файле. Сменили SMTP — риск задеть расчёт. Ревьюер не понимает, что тестировать, и пропускает.
После. Процессор заказывает у «способа оплаты» charge(total) и у «уведомителя» notify(user). Карта и PayPal — два класса с одним договором. Письмо — отдельный уведомитель. В тесте — заглушки: проверка, что charge вызвали с суммой, письмо не уходит на реальный адрес.
Это S, O и D на одном экране. Не надо сразу круги Uncle Bob. Если способов оплаты два и оба пишет один человек раз в год — лестница if честнее пяти файлов. Принцип окупается, когда канал реально добавляют.
Пример 2. Созвон, где буквы есть, сервиса нет
Аня на middle Java. В CV: «SOLID, чистая архитектура, микросервисы». На экране спрашивают: «покажите, где в вашем заказе инверсия зависимостей». Она повторяет определение. Репозиторий — один Django-вид, который ходит в ORM и шлёт письмо. Оффер не про «не знает буквы». Оффер про то, что слова не стыкуются с кодом.
Что сказать вместо алфавита. «Сумму и статус заказа считает доменный сервис. Платёжный шлюз приходит конструктором. В тесте подставляю фейк, в проде — клиент провайдера. Письмо не из этого сервиса: отдельная задача после успешного charge». Если этого нет в коде — не пишите SOLID в файле. Напишите, что сервис считает и куда ходит. Пули: опыт в резюме.
На созвоне senior часто ждут не «я люблю чистую архитектуру», а «вот здесь мы сознательно не вынесли слой, потому что меняется раз в год». Умение не применять принцип — тоже ответ. Подготовка вопросов: interview-prep.
Чистая архитектура — одна фраза, не плакат
За кругами и стрелками: правила бизнеса не зависят от деталей доставки. База, HTTP, брокер, админка — детали. Ядро не импортирует драйвер и не знает, что запрос пришёл JSON-ом. Зависимости смотрят внутрь: адаптеры знают ядро, ядро не знает адаптеры.
Практический выигрыш: тест домена без Docker; смена фреймворка не равна переписке скидок и статусов заказа. Проигрыш: на пет-проекте из трёх эндпоинтов вы неделю рисуете слои и не доходите до README. Рекрутер откроет репозиторий и увидит папки без работающего сценария. Для входа без стажа нужен сценарий: резюме без опыта.
Связь с SOLID: это D, растянутая на систему. Не отдельная религия. Не пишите в CV «Clean Architecture» как стек рядом с Python.
Ревью: как спорить без культа
На ревью «разнеси на слои» без боли в этом файле — шум. Полезный комментарий называет изменение, которое уже случалось или вот-вот случится: «прошлый квартал добавляли второй шлюз две недели, потому что ветка была в process()». Тогда шов — ответ на историю команды, не на букву.
Обратный шум: «не надо интерфейс, у нас же одна реализация». Если тест уже ходит в сеть и падает в CI без VPN — интерфейс окупается сегодня, даже при одной боевой реализации. Если тест не ходит в сеть и шлюз не меняли два года — не рисуйте порты ради конспекта.
Договорённость в команде важнее личного вкуса. Зафиксируйте в двух абзацах: где у нас шов обязателен (платёж, почта, чужой HTTP), где достаточно модуля. Иначе каждый PR — война Фаулера с дедлайном.