Transcription
Парадокс нашего времени. Сияй. Кажется, что мы пишем код в 10 раз быстрее, но потом теряем управление. Добавляем фичу, ломается в трёх местах. Фиксим баг, появляется пять новых. В итоге выкидываем и переписываем с нуля. Это не эффективность, это иллюзия скорости.
Знаете, почему? AI генерит код без понимания архитектуры. Код, который работает сейчас, но не может развиваться. Привет, меня зовут Дмитрий Березницкий. Я в IT уже очень давно. А касательно чистой архитектуры, я начал внедрять её в проекты ещё в 2015 году. За эти почти 10 лет было невероятное количество холиваров, технических разборов и даже переписка с командой Роберта Мартина. На изучение и применение этого подхода потрачено огромное количество времени. И сегодня я покажу, как эти знания работают в постм мире.
Посмотрите на эту сгенерированную картинку. Видите проблему? Конечно, мы с рождения учимся видеть, и сразу понятно, что не так. А эта картинка, всё красиво, пропорции, свет, композиция идеально. А вот листинг написанного кодареквест намного строг. Хороший он.
Если с картинкой мы с вами сразу видим проблему, мы с рождения учимся визуально оценивать мир, то с кодом всё сложнее. Как понять, что LM написал хороший код? SAS Dust пройдены тесты зелёные. Метрики качества в норме. Но знаете что? Всё это не показывает, что всё верно с точки зрения архитектуры. Работа без структуры и понимания того, как правильно приводит вот к чему. Сегодня работает, завтра добавили фичу, сломалось в трёх местах. Через месяц никто не понимает, как оно работает. Через год проще переписать.
Помимо са dust тестов, мы должны ещё и делать всё в такой структуре и архитектуре, которая будет поддерживаема, понятно для человека, понятно для л при следующей генерации. А вот тут уже начинается мастерство, глубокое понимание инженерии и её принципов. И сегодня мы начнём с одного из популярных подходов. Чистая архитектура. Можно даже сказать, что это способ мышления, который позволяет создавать системы, способные развиваться, а не погрезать в багах. Без понимания самой архитектуры и качества мы получаем плохой неуправляемый код, теряем контроль и вообще не можем вносить правки, так как всё становится кашей. Готовы разобраться? Поехали.
Начнём с самого большого заблуждения. Во-первых, ти в клин архитекче - это совсем не то, что вы привыкли видеть свои хоремы. Во-вторых, я покажу, как на самом деле текут данные между своими. И знаете, что? Даже Роберт Мартин тут противоречит себе. Я проведу вас через это противоречие и покажу, как сообщество с ним справляется. В-третьих, мы разберём самый спорный вопрос. Можно ли возвращать доменные энтити из юзкейсов? Этот вопрос буквально раскалывает архитектурные метапы на два лагеря. Я покажу аргументы обеих сторон и, наконец, объясню, почему Spring, Diang Ril и другие любимые фреймворки - это, по сути, антипаттерны чистой архитектуры. Да, да, я знаю, что это звучит как ересь, но факты неоспоримая вещь.
Небольшая предыстория. В 2012 году Роберт Мартин, тот самый Анкл Боб, который подарил нам Solid, опубликовал статью The Clean Architecture. Но он не изобретал с нуля. Он взял идею портов и адаптеров от Алистера Когберна, концепцию луковочной архитектуры от Джефри Палермы, добавил свои 50 лет опыта и создал систему, которая реально работает.
Сейчас я разрушу ваш мир. Entity в Clean Architк - это не то, что многие думают. Поднимите руку, те, кто работал с Kibernate. Assentity Frameworks, Active Record Frails. Отлично. Теперь забудьте всё, что вы знаете про Entity. Серьёзно? Смотрите, что происходит в типичном проекте. Вы создаёте класс user, вешаете на него entity, добавляете table, colм, генерируете getтеры и сеттеры. Стоп, это не титив понимания клин архитекча, это модель хранения данных. Это про то, как хранить данные в базе.
А теперь смотрите, что я имел в виду дядя Боб. Entтив в Clechтекча - это бизнес-объект, который знает свои правила. Это не тупой контейнер данных, это умный объект с поведением. Давайте на примере. Вот банковский счёт в стиле ORM. Поля: ID, банс, number. Методы: Get balance, set balance. Логика. Нет, она где-то в сервисах. А вот банковский счёт в стиле архитек. Поля те же самые методы: депозит, free account, calculate, inserts. Логика вся внутри. Смотрите, метод ведро не просто уменьшает баланс, он проверяет, достаточно ли денег, не превышен ли дневной лимит, не заморожен ли счёт, нужно ли применить комиссию. И все эти правила внутри тити. Почему? Потому что эти правила существовали бы даже без компьютеров. В банке XIX века клерк проверял те же самые вещи просто на бумаге. Роберт Мартин называет это Enterprise Business Rules. Правила уровня предприятия. Они самые стабильные. Правила нельзя снять больше, чем есть на счёте, не изменится даже если вы перейдёте с Постгли на Монга или вообще на блокчейна.
И вот ключевой момент, который многие не понимают. В реальном проекте у вас будет оба типа энтити. В центре богатые доменные entтити с бизнес-логикой. на периферии анимичный RMти для маппинга в базу. Между ними своё преобразование. Да, это дополнительная работа, да, это больше кода, но знаете что? Когда через 2 года заказчик скажет: "Мы переходим на микросервисы" и считают теперь в отдельном сервисе вы просто поменяете реализацию репозитория, бизнес-логика не изменится ни на строчку.
В спорах про анимичные полные модели сломано очень много копий. Это прямой холевар уровня, табы или пробелы. Я не буду устраивать здесь священную войну, но по моему субъективному опыту все проекты, которые мы писали с полными моделями, где логика внутри, получались намного проще в поддержке. Когда бизнес-правила меняется, вы меняете его в одном месте, в энтити. Не нужно искать по всем сервисам, контроллерам, хелперам. Когда новый разработчик приходит в проект, он открывает титити и видит: "А так вот что имеет делать заказ. Всё в одном месте. Никаких сюрпризов". Конечно, выбирать вам. Есть проекты, где анимичные модели оправданы. Простые крутоперации. Возможно, Rich-модели будут овенженирингом. Но если у вас сложная бизнес-логика, если правила меняются, если проект будет жить годами, подумайте о полных моделях. Кстати, если вы не знаете, что такое полные анимичные модели, у меня есть отдельное видео на эту тему. Ссылка в описании, там подробный разбор с примерами.
И вот что интересно в контексте пост lm разработки. Когда даёте lm изучить richмодель, где вся логика внутри тити, он сразу понимает, как работает сущность. Один файл, полное понимание. В анимичной модели логика размазана по десяти сервисам. LM должен изучить всё, и контекстное окно забивается. При правильном промтинге и настроенной раксистеме Rich-модели дают качество генерируемого кода намного выше. Почему LLM видит бизнес-правила прямо в титити? Не нужно собирать логику по кускам из всего проекта. Меньше контекста, больше понимания. Ричь модели в постолом мире - это про эффективную работу с CI, а не просто про частоту кода.
Хорошо, сентити разобрались, они умные и независимые, но кто управляет этим оркестром умных объектов, кто решает, какой entтити когда вызвать? Время познакомиться с дирижёрами. Cases, они же итеракторы. Use - это сценарий использования вашей системы. Один зкейс - одно действие, которое может сделать пользователь. Перевести деньги, создать заказ, подтвердить email. Но почему их называют интеракторами? Потому что они организуют взаимодействие между разными частями системы. Представьте дирижёра оркестра. Музыканты тити знают свои партии, но кто-то должен показывать, когда им вступать.
Давайте разберём на конкретном примере, что делает use case или interactor. Давайте добавим наш слой use case. Сделаем небольшую оговорку. У Роберта Мартина есть input порт и outputпор. Мы пока это упростим и скажем, что у нас есть вот все эти границы, которые у нас на входе в use Case, они обозначают, что интерфейс, то есть внешний клиент какой-то, может быть, какой-то контроллер или ещё что-то делает запрос у юзкейса. Он знает его интерфейс. Соответственно, в Юкейсе есть реализация, и он запрашивает: "Давай переведём деньги от одного пользователя к другому". Передаёт ему идентификаторы пользователей. Что же делает зкейс? Он оркестрирует этот запрос. Для начала ему надо получить информацию об этих пользователях, об их аккаунтах и балансах. И что он делает? Он выходит и делает запрос куда? В, допустим, репозиторий. Но с точки зрения чистой архитектуры он не знает реализацию репозитория. Он также знает интерфейс репозитория. Он знает, что у нас есть методы получения пользователя по его идентификатору или его аккаунта, или балансов, неважно. Репозиторий возвращает нашему юзкейсу, что данные по этим данным или, возможно, entти, чуть попозже мы об этом поговорим, что он может возвращать. Соответственно, use case. Взкейсе у нас появляются entity, и уже говорит самим entity: "Переведи деньги от одного пользователя к другому. совершая эту транзакцию. Тити внутри себя меняют своё состояние. И дальше, если всё прошло успешно, если Entityти сказала, что этот перевод возможен, что у нас нету каких-то ограничений, CASE опять же вызовет наш репозиторий для того, чтобы сохранить обновлённую модель и вернёт ответ уже нашему клиенту о том, что произошло в соответствии с контрактами юзкейса. Давайте я удалю сейчас лишние стрелочки, чтобы они нам не мешали, и пойдём дальше.
Критически важный момент. Интерактор не проверяет баланс, не считает комиссию, не применяет лимиты. Всё это делает тити. Интерактор только знает последовательность действий. Почему это важно? Представьте, у вас появляется новый тип счёта, корпоративный, с другими правилами снятия. Что меняется? Только тити. Интерактор остаётся тем же самым.
Теперь про границы. Это очень интересная идея. И она говорит: "Хочешь со мной работать?" Давай данные в том формате, который мне нужен. И мы получаем с вами границу, через которую также могут переходить данные. Часто через границы у нас какие данные происходят? У нас есть ДТО, который пересекает границу. При этом самкейс может обозначить тот формат данных, который ему нужен. И неважно, тот, кто его вызывает, он получил данные в формате GON, какой-нибудь Yamл или у нас есть там протосообщение или ещё откуда-то. Это всё неважно, потому что CASE принимает данные в том формате, в котором он обозначил, и уже вызывающему надо будет преобразовать данные из своих форматов, формат юзкейса. Тем самым мы защищаем нашу бизнес-логику от изменения, которые происходят в других слоях. Можно сказать, что это в какой-то степени антиuption layer. Есть такой паттерн для того, чтобы мы защищали нашу бизнес-логику от изменения, которые могут происходить вовне.
Давайте уберём всё лишнее. Видите красоту? Case вообще не знает, кто его вызывает и как будет использован результат. Полная изоляция. И вот что важно для работы с LM. US CASE - это идеальная единица для генерации кода. Когда вы даёте я задачу создай зкейс для возврата платежа, он работает в чётких границах, знает, что нужна оркестрация, а не бизнес-логика. М не полезет придумать правила возврата, а не в нтити или детали работы с платёжным шлюзом. Это у нас будет в адаптерах. При правильном промтинге и примерах существующих CASE в контексте AI генерит новые сценарии по той же структуре. Видит паттерн transfer money use case. Создаст Refund use Case с тем же уровнем изоляции. Это как конструктор LEGO. Блоки стандартные, собираешь то, что нужно. CASE в пост мире - это шаблон для эффективной генерации логики оркестрации.
Я ещё одна киллер фича для тестирования. Поскольку все зависимости юзкейса спрятаны за интерфейсами, гейвеи, репозитории, писать тесты становится тривиально. Мокаете репозитории, подставляете тестовые титити, проверяете последовательность вызовов и всё. TDD, юнит-тесты или даже LLM генерация тестов через TDD. Любой подход идеально ложится на изолированные юзкейсы.
Отлично. Теперь мы знаем, кто чем занимается. Entти хранят правила. Интеракторы дирижируют процессом. Но как данные путешествуют между слоями? Вот тут начинается самое интересное и самое спорное. Пристегнитесь, сейчас будет жарко. Сначала напомню главное правило чистой архитектуры Dependency Rule. Роберт Мартин формулирует его просто. Зависимости в исходном коде могут указывать только внутрь. Что это значит? Внешние круги знают о внутренних, но необорот. Контроллер импортирует CASE, US CASE импортирует Entти, Entти импортирует никого. Это железное правило. Ну и вот тут начинается веселье. Для того, чтобы рассмотреть, как происходит поток данных, давайте добавим ещё один слой. Подробно мы его рассмотрим чуть попозже. Это у нас будет слой интерфейс Adapters. Иfей. adдаapters. Что это такое, поговорим чуть позже.
Сначала напомню главное правило чистой архитектуры Dependency Rule. Роберт Мартин формулирует его просто. Зависимости в исходном коде могут указывать только внутрь. Что это значит? Внешние круги знают о внутренних, но не наоборот. Интерфейс-адаптеры знают о существованиейсов, знают про Entity, entity ничего не знает прозкейсы, и Entity ничего не знает ни про какой слой интерфейс-адаптеров. То есть Entity не импортирует никого. Это железное правило. Точка. Но вот тут и начинается веселье. Данные текут в обе стороны. Запрос идёт снаружи внутрь, ответ: изнутри- наружу. Логично. Логично.
Шаг один. Скажем, у нас есть контроллер, в него у нас приходит HTTP запрос, в нём у нас будут JON поля. Контроллер создаст ДТО, о котором знает нашке и трансформирует наш GSON в это ДТО. DТО - это простая структура данных. DТО передаётся в use CASE. USйс понимает, что ему надо сделать, какие там есть данные, и творит какую-то магию entтити. После этого кейс возвращает. Стоп. А что он возвращает? И вот тут начинается Священная война, которая раскалывает сообщество. Роберт Мартин в своей статье двенадцатого года пишет чёрным по белому. Через границы передаются простые структуры данных. Мы не хотим жульничать и передавать энтити или строки из базы данных. Казалось бы, всё ясно. Создавай ДТО и передавай их. Но погодите, смотрите на противоречие. Если контроллер уже зависит от тити, то какая разница передавать класс или экземпляр? Зависимость уже есть. Мы не нарушаем Dependency Rule. Более того, в примерах самого Роберта Мартина есть Entity Gateway, который возвращает тити. Противоречие? Да.
Лагерь за ДТО везде. Полная изоляция слоёв, чёткие контракты на границах, соответствующие букве закона чистой архитектуре. Лагерь за возвращение тити. Меньше кода, нет тон маппинга, выше производительность, нет копирования. Зависимости уже есть на уровне импортов. Кис, но усложнение по необходимости. Мой опыт доказывает использование ДТО везде, если у вас публичный API с версионированием. Entity содержит Sensitти в данные. Разные клиенты требуют разные форматы. Возвращайте, если это внутреннее приложение. Производительность критична, команда маленькая и договорилась об этом.
Важный нюанс. Если возвращать титити, не добавляйте в них аннотации, сериализации, методы для UI, логику специфичную для презентации. Почему? Потому что тогда тити начнёт меняться по двум причинам: бизнес-правила и требования презентации. А это уже нарушение SRP. Ещё раз давайте обговорим этот момент. Если внутри нашей энтити мы добавим какие-либо аннотации, либо её представление для внешнего мира, то есть, допустим, она будет знать, как сделать из себя JON. И этот JON мы хотим отдать кому? Нашему клиенту какому-то внешнему. В какой-то момент этот клиент скажет: "А давайте поменяем какие-то поля". И нам придётся менять либо аннотации, либо титити. А если у нас существуют разные клиенты, которые требуют разные изменения, получится у нас конфликт внутри нашей энтити. Именно по этой причине стоит держать энтити без внешних зависимостей от наших клиентов или слоёв, которые лежат ниже, у которых бизнес-логика может меняться по другим причинам. Поэтому мы с вами удалим Jon либо любые аннотации из нашей Enти и заниматься представлением тити для клиентов. Пускай будет наш слой интерфейс адаптеров, ведь он для того и призван. Для того, чтобы адаптировать внешнее для внутреннего, а потом внутреннее делать из него представление для внешнего. Помните, принципы важнее практик. Если вы понимаете, почему что-то делается, вы можете принять осознанное решение. Теперь вы понимаете, как данные путешествуют и почему это вызывает споры.
Давайте соберём полную картину, какие вообще есть свои и как они взаимодействуют. Пришло время собрать весь пазловый единок. Чистая архитектура - это четыре концентрических слоя. Каждый со своей ответственностью. Представьте их как круги, где самый маленький в центре.
Слой тити - это центр вселенной. Что там живёт? Бизнес-объекты с критически важными правилами. Ордер, который умеет считать свою стоимость. Аккаунт, который знает про овердрафт. Продукт, который понимает свои скидки. Когда меняется, только когда меняются фундаментальные бизнес-правила. Это происходит крайне редко. Правило: нельзя продать товар, которого нет на складе. Оно вечно. От чего зависит? Ни от чего, только от языка программирования. Никаких фреймворков, библиотек или базданных.
Бизнес-сценарии, что там. Вся application specific логика. Create order use case. Он сначала проверяет наличие, потом создаёт заказ, потом отправляет email. Когда меняется, когда меняются требования к функциональности. Добавили шаг подтверждения менеджером, меняется useкеe. От чего зависит? Только от entity. Импортирует доменные объекты и интерфейсы репозиториев и гитвеев.
Слой интерфейс адаптеров - это у нас переходники. Что там у нас? Там могут находиться контроллеры, которые преобразуют внешние запросы, допустим, HTTP Jсона или ещё каких-то форматов в ДТО и вызываюткейс. Также у нас здесь могут находиться репозитории, которые ответственны за хранение нашей модели, либо какие-то гateи, которые заняты тем, что мы выходим из этого сервиса в другой. Также здесь могут находиться множественные сервисы, которые занимаются переходом от одного формата к другому, и множество других переходников, которые могут заниматься связыванием внешнего мира и внутреннего. Когда они меняются? Когда меняются внешние интерфейсы, перешли с рест на гра, меняются только адаптеры. От чего зависит? от USASE и от Entity знает про доменные объекты и интерфейсы.
Слой Frameworks and Drivers или инструменты, что там, всё конкретно техническое. Spring, Postgre, Redes, React, всё, что можно заменить, когда меняется постоянно. Вышел новый спринг, обновляем. Перешли на Монго, обновляем. Перешли на постгреновый версии, обновляем. От чего зависит? От всех внутренних своёв. Видите закономерность? Чем ближе к центру, тем стабильнее. Чем дальше от центра, тем волатильнее. И именно поэтому стрелки зависимости идут внутрь. Нестабильная зависит от стабильного, а не наоборот. И это фундаментальный принцип хорошей архитектуры. Представьте здание. Фундамент - это entitтис, самый стабильный. Несущие стены - это USE, перегородки - это интерфейс-адаптеры. Мебель - это Frameworks and Drivers. Красиво, правда?
Но знаете что? Практически все популярные фреймворки построены с точностью наоборот. Сейчас я покажу, почему большинство фреймворков - это не кlechтек. Сейчас скажу вам холиварную вещь. Большинство популярных фреймворков Spring, Yangang Rils, Laaravell Express построены по принципу фреймворк центр вселенной. Клин архитекча говорит обратно: бизнес-логика центр вселенной. Не поймите неправильно, фреймворки прекрасны, но смотрите, что происходит. Синдром фреймворк везде. Типичный проект на любом фреймворке. Модели наследуются от базового класса фреймворка. Бизнес-логика использует специфичные типы данных фреймворка. Конфигурация через аннотации, декораторы, магические методы. Тестирование требует запуска всего фреймворка. Вы пишите на Python. Ваш Diang проект знает про diangн в каждом файле. JavaScript ваш экспресс пропитывает объектами всю логику. PHP, Laravel модели, везде. Java, спрингнотации в каждом классе. Философия наоборот. Фреймворки говорят: "Я дам тебе структуру, следуй моим правилам". Klerхитекча говорит: Framework - это деталь, которую можно заменить. Примерive record pattern используется в Rails, Diango Rm. Userve модель сама себя сохраняет. Это удобно, но модель теперь знает про базу данных. Бизнес-правило смешалось со способом хранения. Чистая архитектура. Repository save user. Модель не знает, как её сохраняют.
Когда же что выбрать? Framework first подход идеален для MVP прототипов. стандартных крут приложений, проектов с коротким жизненным циклом. Чистая архитектура оправдана для систем с тремя годами жизни, сложный бизнес с логикой и вероятной сменой технологий. Гибрид для прагматиков. Можно использовать фреймворк, но изолировать от него ядро. Бизнес-логика в отдельном слое без импорта фреймворков. Фреймворк только в адаптерах и контроллерах. Dependency injection на связывании своёв. Это компромисс. Больше кода? Да, но когда через 3 года скажут: "Переезжаем с Дианга на Fast API или с Express на next", вы перепишите адаптеры, а не всю систему. Пост lm в мире - это особенно важно. LLM легче понять изолированную бизнес-логику, чем код, переплетённый с фреймворком. Меньше контекста для понимания, лучше генерация.
Окей, теория - это хорошо, но как это выглядит на практике? Давайте проследим путь одного запроса через всю архитектуру. Покажу реальный флоу создания заказа. Предупреждаю, будет много преобразований. Это цена за изоляцию. Итак, к нам приходит наш пользователь, отправляет нам запрос на создание заказа. Запрос у нас будет post, соответственно, какой-нибудь API create order. У нас здесь будет Jon. И в GSON будет информация какой-то товар, Prodct ID, Product ID, может быть, цена и ещё что-то. Этот запрос попадает куда? Попадает к нам в контроллер. И контроллер преобразует эти данные, которые к нам пришли из нашего слоя Frameworks and Drivers, свою какую-то request-модель, mapт на неё, да, назовём это request модель, request model. Эта модель полностью знает интерфейс входящих данных. Дальше контроллеру надо передать управление куда? Вкей, чтобы у нас что-то произошло с нашим заказом. И мы преобразуем нашу requвест-модель во что? В какой-то ДТО с простыми полями, в которые мы переложим информацию о том, что же нам надо создать. И это ДТО у нас перейдёт на управление куда? В нашке CAS получит это ДТО и сможет уже оркестрировать. Либо сначала вызвать репозиторий, получить информацию по кастомеру, либо создать доменную сущность, смотря как что происходит. Представим, что он создаёт доменную сущность из этого ДТО. Доменная сущность у нас полная модель, которая сама следит за своим инвариантом. И если что-то не так будет в момент создания нашей энтити, она проверит свой инвариант. Если вы не знаете это слово, то посмотрите моё видео про полные модели, ссылка в описании. Оно создаёт entти. Если entтити получится, нормально создастся и валидироваться и она не упадёт, то мы что должны сделать? Мы должны её сохранить куда-то. И дальше передаёт это entтити в свой интерфейс-адаптеров непосредственно в репозиторий. Репозиторий может у нас быть реализован с разными базами данных. Может быть даже для хранения одной энтити. Такие случаи бывают, и у нас они были на практике, когда энтити хранилась в разных базах данных. Часть хранилась в блокчейне, часть хранилась в Монге, либо ещё как-то по-разному. Поэтому репозиторий преобразует нашу entтити свою модель для хранения. Да, мы можем сказать, что это у нас будет repa model. Можно назвать её по-разному. Пускай у нас будет это так. Он её преобразует и сохраняет уже в базу данных. Получается, что после сохранения у нас возвращаем обратно в use case информацию. Use case уже отдаёт форматированный ответ. Тут, как мы с вами говорили, либо он может вернуть какую-то ДТО на response, либо он может вернуть Entти непосредственно в контроллер, и контроллер всё возвращает нашему пользователю. Вот такой вот флоу у нас по данным получился.
Итак, давайте ещё раз вкратце. У нас с точки зрения нашего контроллера requestмодель знает, как валидировать GSON. ДTO у нас участвует как контракт между слоями. Вся наша бизнес-логика скрыта в тити. то, как хранится наша модель, сохранено в Repa Models. Их может быть множество в зависимости от того, где и как мы храним. Бывают очень сложные правила к доменным моделям. Часть хранится в одном месте, часть хранится в другом месте. С точки зрения возврата данных сможет вернуть или какой-то отдельный responsнс dto, либо может вернуть нашу entти, и наш контроллер уже преобразует её в ответ, который покажет клиенту. Да, это overhead, да, это больше кода, но меняется API, трогаем только request response. Меняется база данных, трогаем только storage. Меняется бизнес-логика, трогаем только домен. LM бонус, когда просите сгенерировать новый inпоит, он видит чёткий паттерн преобразования. Генерация становится предсказуемой. Много мапинга, да, овенжениринг, возможно.
Ну что, друзья, давайте подведём итоги нашего путешествия по клин архитекча в пост LLM мире. Что мы узнали? Во-первых, тити - это не анимичные модели данных, а полноценные бизнес-объекты с поведением. И для LM это критично. Одна речь-модель вместо десятках разбросанных сервисов. Во-вторых, CASE - это дирижёры, а не свалка логики. Чёткие сценарии, которые LM может понять и воспроизвести. В-третьих, данные текут в обе стороны, но зависимость только внутрь. И да, вопрос ДТО остаётся открытым. Решайте по ситуации. В-четвёртых, фреймворки и клин архитекчи решают разные задачи. Выбирайте по свой контекст.
Критически важный момент про и я генерированный код. Код требует ещё более тщательного ревью, чем написанный человеком. Почему? Если просто принимать сгенерированный без понимания, происходит отток знаний, команда перестаёт понимать собственную кодовую базу. Через полгода у вас чёрный ящик, который как-то работает. Чистая архитектура помогает с этой проблемой. Чёткие границы и изоляции делают ревью управляемым. Проверяете CASE, фокус на оркеestration. Проверяете ти, фокус на бизнес-правилах. Разделяй и властай.
Когда применять чистую архитектуру, сложная бизнес-логика плюс активное использование и яй для генерации. Проект с жизнью больше чем на 3 года с вероятностью серьёзных изменений. Команда готова инвестировать в понимание архитектуры. Когда не применять? Простые круто операции. Framework + AI достаточно. MVP и прототипы скорость важнее структуры. Нет ресурсов на качественный кодрев.
Мой ответ. В эпоху I архитектура - это не про правильно, а про понятно и проверяемо. Начинайте с одного кейса, попробуйте сгенерировать для него тесты через M. Если получается легко, вы на правильном пути. Помните, в независимости от того, пишете вы код или используете UI, архитектура определяет долгосрочность жизни проекта. Чистая архитектура работает в обоих случаях, делая код понятным и управляемым.
Используйте я для кода? Напишите в комментариях, какие проблемы возникают. Обсудим решение. Подписывайтесь на канал. Впереди много практического контента про архитектуру в пост LLM мире. Всем чистого кода и управляемой архитектурой. Пока.