Comments 26
project/
services/
adapters/
rest/
причем если следовать заветам, то содержимое services можно прямо в корень project кидать — ибо «приложение должно кричать»
А в чём заключаются преимущества этого подхода по сравнению с выстраиванием сервиса вокруг данных и операций над ними?
Я возможно смотрю с какой-то странной колокольни (у меня в основном всякие упоротые сервисы: поиск по картинкам, антифрод Авито из сотен rabbitmq-воркеров, просто inference ML-моделей и тому подобное), но никогда не понимал смысла этой движухи.
Она начинает работать только с какого-то определенного объёма проекта или как?
И да и нет, в общем случае действительно можно констатировать, что актуальность проблемы снижается в эру микросервисов. Программист физически не может импортнуть в свой микросервис модуль из другого микросервиса. Тем самым установив между ними связь в обход API.
Другой момент, что многие микросервисы несут утилитарный характер и содержат минимум бизнес-логики, во некоторых моих сервисах, services занимает около 10% от общего объема кода.
Но, даже в таком случае я вижу все преимущества о которых говорится в статье, к тому же, микросервисы также имеют свойство расширяться, и стало быть применение Сlean Archetecture это задел на будущее.
Еще один бонус — в микросервисной архитектуре сервисы в основном взаимодействуют друг с другом посредством обращения к их АПИ, и это очень хорошо вписывается в предложенную модель, если ORM нас как-то абстрагируют от БД, то обвязки API придется писать самим.
Ну а самое главное: если начинать с модели описанной в статье то оверворк будет совсем небольшим, и сполна перекрывается плюсами.
К сожалению, эти заделы на будущее почти никогда не пригождаются, так и оставаясь навсегда мусорным кодом, маскирующим суть происходящего. Вы и сами ниже об этом пишете, когда говорите, что предсказать что именно будет нужно очень трудно.
Я для себя выбрал более очевидный подход: сервис должен решать задачу самым простым из удовлетворяющих требованиям способов и его архитектура должна определяться задачей.
Когда следуешь советам признанных мастеров, типа того же Мартина, всегда нужно узнавать о контексте в котором был дан совет, вполне возможно что для него сервис — это весь бизнес целиком, который разрабатывают человек 200, тогда его советы начинают реально помогать.
Так недавно к нам приезжал Крис Ричардсон и рассказывал про то, как правильно делать микросервисы: он говорил, что должен соблюдаться принцип "один микросервис на команду", а у нас на команду из 7 человек уже полтора десятка микросервисов и это действительно удобно.
На всякий случай добавлю, что необходимость включать мозг при добавлении новой функциональности ни один из подходов не отменяет :)
По идее, как и любая архитектура. Как только проект начинает расти вширь и приходится много работать с кодом, то тут начинаются проблемы с тестами, поддержкой кода и т.д, если архитектура плохая
Думаю для вашего примера нужно просто нафигачить sql в контроллере и не парится. После этого можно задаться такими вопросами:
- Что должно измениться в проекте, чтобы sql в контроллере перестал быть самым простым и понятным решением?
- Какие есть вообще варианты ответа на возникшее изменение?
- Чем выбранный вариант, лучше всех остальных?
Если на эти вопросы отвечает человек с хорошим техническим кругозором и знанием предметной области — будет вам хорошая архитектура. А clean, onion, MVC, все что угодно это попытки предложить фиксированный набор примитивов, в терминах которых нужно описывать ваш бизнес. Это никогда не работает в долгосрочной перспективе и всегда добавляет уйму ненужного кода.
Совершенно верно, пример (не мой) совершенно гротескный, зато в нем хорошо видно тот минимальный оверворк, который несет предложенный подход, посмотрите еще раз он совершенно не большой.
> Что должно измениться в проекте, чтобы sql в контроллере перестал быть самым простым и понятным решением?
Мой опыт говорит что ответить на этот вопрос в сколь-нибудь отдаленной перспективе совершенно невозможно, даже в данном примере, бизнесу может потребоваться все что угодно:
— ранжирование на основе предпочтений пользователя
— добавление в топ партнерских материалов
— расчет скидок,
а еще отправить евент о событии и тд.
И спрогнозировать во что это может вылиться совершенно невозможно, сколько не погружайся в предметную область, потому, что потребности бизнеса имеют особенность постоянно меняться, такова его природа
> всегда добавляет уйму ненужного кода
Основную массу ненужного кода составляет маппинг структур которые движутся между слоями, такие библиотеки как pydantic, позволяют его минимизировать.
Ну а отсутствие необходимых примитивов и одновременное накачивание проекта быстрыми фичами могут превратить весь проект — в «уйму ненужного кода»
Мой опыт говорит что ответить на этот вопрос в сколь-нибудь отдаленной перспективе совершенно невозможно
Кажется бизнес тут совсем ни при чем. Вот моя попытка ответить на эти вопросы. Исходная ситуация — есть функция, которая мапит запрос в sql, выполняет его и возвращает результат.
Что должно измениться в проекте, чтобы sql в контроллере перестал быть самым простым и понятным решением?
— мапинг в sql может стать очень сложным.
— части мапинга могут дублироваться между разными функциями.
— выполнение sql может стать более сложным, может быть шардирование базы появилось, может кеш добавился
Какие есть вообще варианты ответа на возникшее изменение?
— Сложный мапинг — специфический builder объекты, query object, просто вытащить часть логики в другой объект, назовем его «сервис», «репо», «контекст» — не важно, лишь бы другие члены команды были согласны, что все по фен-шуй.
— Повторное использование мапинга — опять же builder/criteria, возможно репо. Мой личный фаворит для C# — extension method для DbContext или builder/criteria.
— Хитрое «выполнение» с кешами, шардингом и т.п. — можно все прямо в контроллере сделать, дернуть кеш или из shard manager получить соединение с нужной базой. Но тут возможны варианты.
Сложные объекты с логикой внутри ala DDD появятся только если
— Есть логика, эквивалентная машине состояний с хотя-бы десятком состояний.
— Нужно обрабатывать в памяти сложные объекты. Пример — счет клиента на бирже, связанные с ним ордера, балансы и всякие настройки комиссии и прочее.
Для всех интересующихся чистой архитектурой и DDD могу посоветовать посмотреть на проект dry-python — набор библиотек для написания сложных бизнес приложений.
Пример как это выглядит на живом репозитории: github.com/dry-python/bookshelf
Доклад clean architecture для django приложений: www.youtube.com/watch?v=tKEv9Enhm1Q
Дорогой @profit404, я даже добавил ссылку на dry-python в конце статьи, но почему же Вы выкатили свои ссылки, не добавив столь нибудь существенного комментария по тексту статьи (
Прочитал про data classes и подумал: почему ничего про них не помню? Оказалось, всё просто: потому что, если используешь attr.s, то они нафиг не нужны :)
Узнал про этот модуль в монументальном цикле статей "asyncio: We Did It Wrong ", проникся и с тех пор без него как без рук.
В оф. документации написано, почему эта штука лучше, чем data classes, named tuples и т.д.
Очень коротко: нам предлагают больше плюшек при том, что хотят от нас меньше бойлерплейта и оперативки
Однако, в приведенном Вами «плохом» примере от Леонардо присутствует валидационая обвязка, которая в Вашем «хорошем» примере неявно скрыта внутри FastAPI. Не знаю, что мешало Леонардо ввести в его код это логичное усовершенствование.
Если за определение MVC брать статьи habr.com/ru/post/321050 и habr.com/ru/post/322700, то что в старом примере, что в новом MVC один и тот же.
Clean Architecture глазами Python-разработчика