Здравствуйте, 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>То есть прделагают два агрегата. 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. (с) Т.е. никакого научного обоснования, а такая же веря как с ДДД.
Здравствуйте, Sinclair, Вы писали:
S>>Какие, например? S>Банальные вопросы вроде "зарезервировать товары заказа на складе". S>Потому что в домене есть складские остатки, есть товары, есть заказы. Ни в кого из них запихать метод "зарезервируй" не получается без того, чтобы втащить внутрь этого метода не-доменную логику. S>А делать специальный AggregationRoot, который типа и должен всё это делать, противоречит самой идее Ubuquitous Language, т.к. этого рута в "домене" не существует.
Это странно, почему так нельзя делать? А как тогда машину описать, ведь ее не существует, а существуют колеса,
кузов, двигателя, трансмиссия, ходовая часть и т.п. Но очевидно в соотв. домене будет что-то типа Car или Automobile и т.п.
именования.
Кодом людям нужно помогать!
Re[37]: Что если не разделять строго dto, entity, bo...
Здравствуйте, Sharov, Вы писали:
S>На питоне как-то солиднее решение, да делать дольше и сложнее, но надолгосрок будет проще.
Эт, в принципе, резюмирует всю дискуссию.
С такой точкой зрения идеальный код для 2*2 будет new MultiplierFactory.get_default_multiplier().set_first(a).set_second(b).execute().get_result(); Он гораздо солиднее.
Напомню для остальных читателей темы, что нет ни одного свидетельства о том, что более длинный код будет "проще на долгосрок". Множество свидетельств обратного.
Но вера в "солидность" непоколебима и видимо никакие разумные аргументы не могут её разрушить.
Re[37]: Что если не разделять строго dto, entity, bo...
Здравствуйте, Sharov, Вы писали:
S>Я так и думал -- correlation doesn't imply causation. (с) Т.е. никакого научного обоснования, а такая же веря как с ДДД.
Это называется "когортные исследования". В пирамиде медицинских доказательств они например занимают третье место. Второе за рандомизированными плацебо-контролируемыми исследованиями, а первое — мета-анализы. Когда провести рандомизированный эксперимент невозможно, то когортные исследования признаются достаточно хрошим источником доказательств.
Напомню что про DDD вообще нет ни одного исследования, которое хоть какие-то измеримые результаты дает. Там все "доказательства" это просто мнения людей. Причем изначально довольно небольшой группы. Сейчас люди часто приводят пример из книги Эванса (которой уже 20+лет), а когда доходит до примеров реалистичных и актуальных — уже не так хорошо даже на них ДДД работает.
Так что вера ДДД гораздо сильнее, чем вера в ООП или agile.
Re[38]: Что если не разделять строго dto, entity, bo...
S>>Я так и думал -- correlation doesn't imply causation. (с) Т.е. никакого научного обоснования, а такая же веря как с ДДД. G>Это называется "когортные исследования". В пирамиде медицинских доказательств они например занимают третье место. Второе за рандомизированными плацебо-контролируемыми исследованиями, а первое — мета-анализы. Когда провести рандомизированный эксперимент невозможно, то когортные исследования признаются достаточно хрошим источником доказательств. G>Напомню что про DDD вообще нет ни одного исследования, которое хоть какие-то измеримые результаты дает. Там все "доказательства" это просто мнения людей. Причем изначально довольно небольшой группы. Сейчас люди часто приводят пример из книги Эванса (которой уже 20+лет), а когда доходит до примеров реалистичных и актуальных — уже не так хорошо даже на них ДДД работает.
Согласен, но все равно это так себе исследования. Будем тут честны.
G>Так что вера ДДД гораздо сильнее, чем вера в ООП или agile.
Спорить не буду.
Кодом людям нужно помогать!
Re[38]: Что если не разделять строго dto, entity, bo...
Здравствуйте, gandjustas, Вы писали:
S>>На питоне как-то солиднее решение, да делать дольше и сложнее, но надолгосрок будет проще. G>Эт, в принципе, резюмирует всю дискуссию. G>С такой точкой зрения идеальный код для 2*2 будет new MultiplierFactory.get_default_multiplier().set_first(a).set_second(b).execute().get_result(); Он гораздо солиднее.
Речь про долгосрок, про подстелить себе салому, а не дурака валять с ООП. Все-таки на долгий срок
если выбирать, то питон решение выглядит солиднее, чем sql скрипт + обвязка на C#. Во втором случае скорее
всего во что-то упретесь и придется переписывать с нуля, а в первом добавить немного кода.
G>Напомню для остальных читателей темы, что нет ни одного свидетельства о том, что более длинный код будет "проще на долгосрок". Множество свидетельств обратного. G>Но вера в "солидность" непоколебима и видимо никакие разумные аргументы не могут её разрушить.
Также напомню читателям, что моделировать модель предметную область гораздо лучше, чем обновлять соотв. строки в бд.
Да, дольше и сложнее, но на долгосрок самое то.
Кодом людям нужно помогать!
Re[39]: Что если не разделять строго dto, entity, bo...
Здравствуйте, Sharov, Вы писали:
S>Также напомню читателям, что моделировать модель предметную область гораздо лучше, чем обновлять соотв. строки в бд.
Для этого утверждения нет никаких доказательств.
Здравствуйте, Sharov, Вы писали:
S>Это странно, почему так нельзя делать? А как тогда машину описать, ведь ее не существует, а существуют колеса, S>кузов, двигателя, трансмиссия, ходовая часть и т.п. Но очевидно в соотв. домене будет что-то типа Car или Automobile и т.п. S>именования.
Вот такие примеры — вредны. Они не решают реальную проблему, и иллюстрируют удобство написания кода, который вообще не надо писать.
Точно так же, как примеры про наследование фигур. Я уже неоднократно говорил — ни в одной системе вам не потребуется наследовать фигуры друг от друга; скорее всего, единственная фигура, которая вам потребуется — это PolyLine. А наследования с полиморфизмами появятся там, где вы будете этот Polyline обрабатывать — ну там, растеризовать, или превращать в SVG, или в метафайл.
Так и с автомобилем — скорее всего, у вас не будет полиморфного объекта "Car" с объектами, из которых она состоит.
Будет, скорее всего, какой-то объект типа ComplexAssembly, с умением "состоять из".
При этом никакого поведения, кроме "состоять из", у него не будет. Всё остальное будет делать какая-то внешняя по отношению к нему логика — собирать, учитывать, регистрировать, отгружать заказчику и т.п.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[39]: Что если не разделять строго dto, entity, bo...
Здравствуйте, Sharov, Вы писали:
S>Речь про долгосрок, про подстелить себе салому, а не дурака валять с ООП. Все-таки на долгий срок S>если выбирать, то питон решение выглядит солиднее, чем sql скрипт + обвязка на C#. Во втором случае скорее S>всего во что-то упретесь и придется переписывать с нуля, а в первом добавить немного кода.
Скорее всего наоборот: в питоновом решении упрётость наступит примерно сразу, и придётся переписывать всё это нагромождение паттернов друг на друга.
А в С# кода мало, даже если его придётся целиком переписать — не жалко. Да и переписывать-то скорее всего не придётся — учёт статусов и чего угодно делается добавлением предикатов к запросу.
Как только предикаты становятся сложными и начинают использоваться в нескольких местах — код уезжает из каждого конкретного запроса в функцию, которой пользуются все:
var db = ctx.Database;
await db.CreateExecutionStrategy().ExecuteAsync(async ct =>
{
await using var t = await db.BeginTransactionAsync(System.Data.IsolationLevel.Serializable, ct);
await ctx.Issues.Where(i => i.Id == id).ExecuteUpdateAsync(s => s.SetProperty(x => x.UserId, userId), ct);
if (await ctx.СountUserIssues(userId, ct) > ctx.GetMaxUserIssues(userId)) throw new Exception("Auchtung");
}, ct);
S>Также напомню читателям, что моделировать модель предметную область гораздо лучше, чем обновлять соотв. строки в бд.
Вопрос не в том, моделировать ли. Вопрос — в том, как моделировать.
Тот самый Липперт же не предлагает отказаться от программирования D&D. Он предлагает другую модель, которая, в отличие от наивного подхода с new Warrior(), работает. S>Да, дольше и сложнее, но на долгосрок самое то.
Нет.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.