Здравствуйте, gandjustas, Вы писали:
S>>>>Ну тактические все-таки что-то новое, все эти agg root, transaction script, entity, values. А так да, взяли отовсюду понемногу.
G>Абсолютно не связанные между собой вещи. Микросервисы ничего не говорят об архитектуре внутри сервиса.
Тактические и стратегические да, не связаны. Зачем-то их убрали под один зонтик ДДД. На счет арх-ры
микросервисов -- ну приставка микро должна говорить о том, что все-таки желательно иметь что-то простое.
Т.е. в идеале микросервис должен говорить об очень простой архитектуре.
S>>Ну а Эванс добавил стратегические паттерны и превратил все это методологию. Что называется стоял на плечах гигантов.
G>Как я и написал ниже он добавил философию.
1)Это, кстати, важно. Кроме шуток. Философия вещь важая и нужная.
2)Все-таки он превратил все это дело в методологию.
S>>Соглашусь. Ну, кстати, и ООП тоже своего рода мода.
G>На ооп мода была в середине девяностых — середине нулевых. Мода прям адская, все что не ООП — было "фу". На волне этой моды ДДД и появилось.
G>Потом микрософт нанял Эрика Мейера, который до этого Хаскелем занимался и он всех покусал функциональщиной, а в 2011 вышел стандарт с++11, в ктором вся стандартная библиотека была функциональной.
G>На той волне даже JS голову поднял, в нем давно было то, что в мире ФП ценилось.
Да, помню эти времена и по срачам в жж и тут. Машинное обучение все это снесло или сделало мало релевантным.
Народ перенес свой фокус туда.
S>>Странно, учитывая что он на 20 лет появился раньше. А на питон почему не смотрели, вроде для него уже были фреймоврки для веба?
G>Возраст языка не показатель популярности. в 2005 на полках книг по C# и Java было одинаково, даже по C++ было меньше, хотя он старше. А по перлу если одна попадалась на полке, то лежала там несколько лет.
В библио-глобусе до фига была книг по любой технологии, бывал там в 2005-2010 очень и очень часто.
Но это в Москве. Хотя думаю, и в любом крупном областном центре были свои хорошие книжные.
S>>При чем здеьс обеспечение инварианта и ДДД?
G>Видимо это никак не связанные вещи
Видимо.
S>>Объектами самой бд, типа строки\колонки\талбицы и т.п.
G>У слова "объект" в программировании есть вполне конкретное значение. строки\колонки\талбицы не являются объектами с точки зрения работы с БД.
С тз реализации вполне являются.
S>>Я пытаюсь настоять на его полезности хотя бы в рамках распила монолита на микросервисы.
G>Ок, давай примеры чем именно ДДД помогает. А еще было бы неплохо описать "механизм действия", а то может ДДД не при чем.
G>Или нам поверить что помогает потому что кто-то сказал?
Берете монолит, находите в нем домены, в доменах BC и по этим BC микросервисы и нарезаете. Желательно чтобы
1 BC — 1 agg. root. Но это, кажется, не обязательно.
G>>>Бремя доказательство обычно возлагается на того кто утверждает, пока он не представил объективные аргументы.
S>>У меня их нету
G>Ок, значит просто вера
Как и в эффективность ООП, получается.
S>>Давайте разберем контрпример. Хотя думаю, что мое утверждение выше было чрезмерно сильным. Возможно ДДД ничего такого не утверждает.
G>Допустим разрабатывается система, аля трекер. Заказчик хочет возможность ограничить количество задач для пользователя.
G>Будут две сущности: Issue и User, связанные много-к-одному.
G>У Issue есть метод AssignTo, которому надо передать User или его Id, чтобы связать. И надо как-то гарантировать что выполняется условие, что для одного User назначено не более трех Issue/
G>Какую реализацию нам диктует прагматичный подход (ПП):
G>Прямо в контроллере, в одной транзакции (!) сделать два запроса:
G>G>update issues set user_id = @userid where id = @id;
G>select count(*)from issues where user_id = @userid
G>
G>Для PG и других баз с оптимистичными блокировками нужен уровень изоляции serializable и повтор запросов при ошибке, а для SQL Server без RCS и MySQL (и других блокировочников) достаточно read committed
G>Реализация на C# для postgres может выглядеть так:
G>G>var db = ctx.Database;
G>await db.CreateExecutionStrategy().ExecuteAsync(async ct =>
G>{
G> await using var t = await db.BeginTransactionAsync(System.Data.IsolationLevel.Serializable, ct);
G> await ctx.Issues.Where(i => i.Id == id).ExecuteUpdateAsync(s => s.SetProperty(x => x.UserId, userId), ct);
G> if (await ctx.Issues.CountAsync(x => x.UserId == userId, ct) > 3) throw new Exception("Auchtung");
G>}, ct);
G>
Для MVP сойдет, а для какого-нибудь аналога джиры такое себе.
G>С этой же задачей я пошел в рекомендованный тобой чат, попросил показать пример DDD. три дня срачей, рассказов что я не умею требования анализировать, что задача вообще нереальная и не надо её решать итд.
G>Самое лучшее что один из участников написал пайтоне
G>G>class User(DomainEntity[UserId]):
G> def __init__(self, entity_id: UserId, issue_count: int) -> None:
G> super().__init__(entity_id)
G> self._issue_count = issue_count
G> def take_issue(self) -> None:
G> MAX_ISSUE_COUNT = 3
G> self._issue_count += 1
G> if self._issue_count > MAX_ISSUE_COUNT:
G> raise TooManyIssues
G>class Issue(DomainEntity[IssueId]):
G> def __init__(self, entity_id: IssueId, metadata: str, user_id: UserId | None):
G> super().__init__(entity_id)
G> self._metadata = metadata
G> self._user_id = user_id
G> def assign_to(self, user: User) -> None:
G> if self._user_id:
G> raise IssueIsAlreadyAssigned
G> user.take_issue()
G> self._user_id = user.entity_id
G>
G>То есть прделагают два агрегата. User хранит счетчик issue. Причем в реальности такая логика будет размазана по разным файлам.
G>1) Во первых код тупо не полный, так как кроме увеличения при назначении надо еще уменьшать при переназначении.
G>2) Как будет обеспечиваться изоляция транзакций непонятно, этого кода также нет.
G>А теперь представим что программа у нас развивается и требования чуть усложнились: теперь надо считать не все Issue, а только в нужном статусе.
G>В варианте на C# добавить фильтр и код проверки вызывать как в методе назначения задачи, так и при смене статуса на нужный.
G>Что делать в варианте на пайтоне — даже боюсь представить.
G>Получается что сделали по ДДД максимально хорошо насколько люди поняли ДДД, а получилось раздутое нерасширяемое и скорее всего ненадежное говно.
Нерасширяемое оно получилось как раз на С# -- начните получать певрые пожелания и доработки от заказчиков, а играться
со статусами и привет. На питоне как-то солиднее решение, да делать дольше и сложнее, но надолгосрок будет проще.
S>>Блин, ну как тогда любая технология взлетает, если в нее по сути по началу верять пару человек, если вообще не один? При таком подходе никакого ООП бы не было.
G>Серьезно считаешь что ООП родилось из веры?
G>ООП родилось из решения частных задач, а именно моделирования поведения в агентной системе. Внезапно первый ОО-язык это была в первую очередь агентная система.
G>Авторы ООП никуда ООП не продвигали. Последователи сами захотели включить его в свои языки, причем сильно по разному.
G>От появления ООП до первых популярных языков прошло почти 20 лет.
G>Больше всех ООП популяризировал C++, потому что он по сути добавлял новые фичи в адски популярный тогда С. Возможно если бы не Страуструп то такого хайпа и не случилось бы.
G>Популярность ООП это скорее череда совпадений и неплохой изначальной идем, которую специально никто не форсил.
А откуда была уверенность в неплохой изначальной идеи? Т.е. это был прагматичный расчет? А куда девать тогда
череду совпадений?
G>А с DDD ровно обратная картина.
Блин, кучу всего объединил под один зонтик (см. выше) и попытались приделать какую-то методологию.
Что там обратного -- не понятно.
G>>>Насчет solid не знаю, про agile и рефакторинг находил.
S>>Ну вот про научно доказанную пользу agile я бы почитал.
G>Да там банальное исследование было: опрос какие практики применяют и считали корреляцию с "успешностью" проектов. Как успешность считали уже не помню.
Я так и думал -- correlation doesn't imply causation. (с) Т.е. никакого научного обоснования, а такая же веря как с ДДД.