Pull to refresh
61

Architect | Lead | Senior Developer

13
Subscribers
Send message

Да, да, вы как бы больше боролись с графом зависимостей в NestJS и TypeScript. C# как будто бы в этом плане получше и проблема сложности перетекает на новый уровень.

И я еще забыл упомянуть один критерий в плане организации кода. Выделение каждого бизнес-метода в отдельный класс - снижает шанс на конфликты мержа в системах контроля версий. Это когда над проектом работают много людей и, допустим нескольким из них в спринте поставили задачи, которые затрагивают один большой файл - условный UserService. Чем мельче дробление, тем меньше шанс конфликта.

Вот это автора утилиты бомбануло 😅

Насколько я понял основная идея - это выделить каждый метод из service в handler и затем как из кирпичиков строить дом. И направление зависимостей. Но, скажем так, в C#, которым я пользуюсь, у меня никогда не было проблем с циклическими зависимостями. Но проблемы все равно остаются.

External service в итоге вырождается в тот же самый бывший service, только внутри не собственно бизнес код, а вызовы хендлеров.

С тем же успехом можно было сделать так

interafce ICreateUserHandler
{
  Result CreateUser();
}

interafce IGetUserByEmailHandler
{
  Result GetUserByEmail();
}

interafce IUserServiceExternal : ICreateUserHandler, IGetUserByEmailHandler
{
}

class UserService : IUserServiceExternal
{
  Result CreateUser()
  {
    ...
  }

  Result GetUserByEmail()
  {
    ...
  }
}

И в контроллер инжектить именно IUserServiceExternal, но не плодить 100500 классов хендлеров. То есть формат размещения кода особо не влияет.

Я то в своих проектах тоже пришел к этим условным handler, и так, чтобы их можно было собирать в цепочки еще, внутри оркестраторов или внутри друг друга (это кстати отражает BMPN / IDEF0). Но по результату могу сказать, что это особо не помогло побороть сложность.

Хендлер вроде бы один, но начинают появляться условные ветки, от которых код внутри хендлера должен вести себя немного по разному. Ну например когда создаем заказ из UI и из API, там немного разные правила. Начинаешь думать, что с этим делать. И там дилемма - либо делать два хендлера, где по началу 95% одинаковое (привет дублирование и любое изменение, которое нужно в двух хендлерах - нужно не забыть делать в двух хендлерах). Либо начинать мутить и выводить общий код в новый общий хендлер, либо делать что-то вроде шаблонных методов, или цепочек декораторов. И все снова скатывается в говнокод и кучу зависимостей.

И еще я все же ждал в статье блок, посвященный транзакциями. Там это реально проблема.

Вот пример недавней новой фичи.

Мы обрабатываем заказы в фоновом режиме. У нас есть хендлер, который качает их из внешней системы, там же обернуто в транзакцию и retry policy, причем как к внешней системе, так и в момент сохранения в БД. Далее у нас есть хендлер на обработку заказа, хендлер на отмену, хендлер на удаление. Каждый из них в транзакции и обернут в retry policy. Эти бизнес-процессы были сделаны ну допустим пару лет назад.

И вот приходит запрос сделать задержку в обработке заказов. Мы его должны скачать, сохранить, обработать частично (чтобы резерв товара прошел), но не отправлять на склад. И потом просто ждать. По истечении времени, например 4 часа - нам надо заново скачать заказ из внешней системы (потому что он мог изменится за 4 часа) и снова прогнать через процессинг. Но! По другим бизнес правилам, мы не можем дублировать заказы и нам надо как-то умудрится снять резерв, не потеряв его (потому что мы пообещали уже, что у нас есть товар под первую копию заказа).

То есть нам сначала надо прогнать отмену и удаление первой копии ордера и только потом создать новый. То есть, набирая этот новый процесс существующими хендлерами - оркестратор выглядит так

1. Handler 1: Скачать новую копию заказа
  a) тут внимание, некоторые внешние системы требуют отправить подтверждение,
    что мы скачали заказ, но мы не можем это сейчас вызвать, потому что 
    мы еще не сохранили новую копию заказа, то есть нам надо вызывать этот 
    хендлер как бы частично
2. Handler 2: Отменить старую копию
  а) Handler 2-1: Отменить отгрузки (1 .. N) [у нас на UI есть кнопка 
     для отмены одной конкретной отгрузки, то есть это реально еще один 
     вложенный самостоятельный хендлдер]
  б) Handler 2-2: Отменить сам заказ [отменить заказ без отмены всех 
     вложенных отгрузок нельзя]
3. Handler 3: Создать заказ (он уже и так вызывается из трех мест - 
   UI, API, плагины/вебхуки)
4. Handler 4: Запустить обработку заказа, но без отправки отгрузкок на склад, 
   это фоновая операция, там у нас очередь [это еще один пример хендлера, 
   который тоже вызывается из 2-3 мест, но именно тут надо его вызывть 
   частично как бы]
5. Handler 5: На самом деле это продолжение Handler 1, потому что теперь 
   наконец-то мы можем подвердить внешней системе, что мы скачали новую 
   копию заказа 

И вот теперь представьте, что каждый хендлер тут имеет свою retry policy, этот оркестратор может упасть на ЛЮБОМ этапе, но нужно обеспечить повторяемость этой сложной операции, потому что, если мы потеряем заказ - клиент придет с жалобами и нам придется заплатить штраф.

Ну и чтобы жизнь медом не казалась - DDD тут не совсем поможет, потому что в первую очередь оно начинает тормозить на постоянных операциях восстановления сущности/агрегата из хранилища и потом сохранения нового состояния. Например хендлер "отмена отгрузки" внутри вызывает хендлер "возврат резерва товара". Это работа со складом, которая может быть выполнена только в один поток (чтобы не продать больше, чем есть на складе) и надо максимально ускорить и стабилизировать этот процесс, избавившись от кучи лишних обращений по сети и длинных транзакций. И в итоге этот модуль лежит в хранимых процедурах в БД, и все операций выполняются за один сетевой вызов к БД.

Так то эта вся канитель существует уже давно, сколько я себя помню программистом. То есть найм был сломан всегда в этом плане. Просто раньше это решалось откликом на след вакансию. Сейчас вакансий мало, людей много. И обсуждать сломанный найм массово начали только в последний год-два.

Ну вот, на самом интересном месте, давайте вторую часть 🫠

Вот как надо троллить этих ИИ ботов
А что ж мемную картинку не вставили в статью?

Только недавно попалась статья, что какой-то там набор castle вырос в цене на over 9000%

У меня никогда не было проблем с тем, чтобы накопить. Как-то само копилось. Родители всегда говорили надо на черный день откладывать, видимо отложилось на подсознании. И супруга экономная оказалась 😊, хотя было так, что ее зп - это "ее", а моя - это "наше".

Ну и однажды я задумался - а куда их девать? Но прежде чем прийти к этой мысли - должно было случится несколько событий. А именно - закрыть все свои гештальты из детства, юности и молодости. Как то - купить себе тот смартфон, который всегда хотел. Или компьютер, или машину, или квартиру. Побывать в тех местах, о которых мечтал или хотя бы интересовался. А если еще дети есть - там еще целый пласт расходов. Так что 500к даже в течение лет 5-7-10 подряд может не хватить.

Таким образом, пришлось сначала обзавестись квартирой, машиной, слетать в США, Мексику, помочь родителям с жильем в столице, не говоря уже о смартфонах последней модели себе и супруге, ноутах и компьютерах.

Все это заняло определенное время. И вот в возрасте примерно 35+ лет, когда все хотелки наконец-то были удовлетворены, в голове возник философский вопрос "а что делать дальше?"

Книжек про инвестирование я не читал. Поэтому методом проб и ошибок. По итогу, чисто по-моему опыту - инвестиции это отдельная работа. И теперь краткая справка, что пробовал я или мои знакомые и что из этого вышло.

Муть:

  • Вложения в совместные бизнесы с друзьями - туфта, все прогорело

  • Всякие мутные инвестиционные схемы в банках, например через разбиение суммы вложений на части и распределение по корзинкам - это самая мутная муть, надо очень внимательно читать условия выхода мелким шрифтом со звездочкой. Я не повелся. Но это событие (меня банк заспамил) привело к тому, что я решил попробовать SP500 и о нем ниже

  • Управление через брокера - наверное, если брокер - это ваш друг, то будет надежней, но знакомый повелся и ничего не смог вернуть. Опять же какие-то мутные условия выхода мелким шрифтом со звездочкой.

Наверное не муть, если задним умом:

  • Недвижка, с вводом эскроу счетов, льготной ипотеки и пандемии - цены взлетели раза в два. Но это в долгосрок. Надо сидеть и ждать, и платить налоги и ЖКХ.

  • Просто тупо сидеть в валюте. Опять же это в долгосрок - тренд всегда в рост, даже с регулярными ямами. Но за все время только один раз удалось продать действительно "на хаях", когда доллар был 118.5 руб. В большинстве случаев как повезет, думаешь ну вот 80, продал, а завтра 100. Тут кстати, если бы не вкладывался в бизнесы друзей - ничего не прогорело бы и еще "заработал" бы больше.

Похоже, что не совсем муть:

  • Депозиты в банках - подходит для поддержания штанов, но нужна весомая сумма (от 5 миллионов) и процентная ставка 15-20%, чтобы выхлоп был не копеечный. Тогда этого хватает, чтобы покрыть ощутимую часть текущих ежемесячных расходов. Прямая работа капитала. Но все это время основная сумма медленно сгорает.

  • Но больше всего понравился SP500 - 20% в валюте в первый год, только если бы не 2022 год 😅

Вот так и живем.

Вот кем надо быть чтоб пройти все собесы в Яндекс! И это с учетом того, что с алгоритмами там работают аналитики, а не программисты 🫠

А прикиньте еще есть товарищи, которые НЕ учатся все это время и застревают. Делают одни и те же ошибки. Не меньшее мучение со стороны старших разработчиков и лидов.

Слабый движок? Типа 1.6? Плюс вариатор

Там чем мощнее, тем меньше расход 😅

На солярисе с 1.6 у меня расход был 12-14 в городе

На тигуане с двухлитровым турбо-движком 10-12, на мазде с 2,5 литровым турбо расход примерно 11.

Кстати на ваз 2112 был вроде что-то между 12 и 14, если мне память не изменяет.

А еще интересно было бы сравнить с mongo db или любой другой бд, заточенной под хранение json

Нет, не путаю.

Так то в DDD много всего. И в книгах про DDD есть примеры диаграмм, кода на тех или иных языках программирования (там классы, ООП, и все такое). Концептуально DDD построено на том, что оно независимо от всего остального (и БД в том числе)

И следовательно, требуется загружать состояние агрегатов и сущностей из хранилища в память компьютера (это можно сделать как через ORM так и другими способами), потом производить некоторые операции и затем сохранять новое состояние в БД. Это отвязывает DDD от конкретного хранилища и позволяет писать быстрые юнит тесты на доменные объекты и бизнес-логику.

Но как раз тут и начинаются тормоза. И все подобные статьи поверхностны и не отвечают на неудобные вопросы. Ну а хранимые процедуры на то и называются процедурами - это по сути анемичная модель (в виде таблиц) и отдельно "код с бизнес-логикой".

А где среди всего этого переход на нативный sql и бизнес логику в хранимках, потому что этот ваш DDD дико тормозит?

У нас мульти-тенантная b2b, логическое разделение, транзакции, тесты на ui только начинаем, так что с буфером обмена пока не столкнулись.

Information

Rating
4,322-nd
Location
Россия
Registered
Activity

Specialization

Бэкенд разработчик, Архитектор программного обеспечения
Старший
C#
.NET Core
SQL