Re[47]: Как внедряли DDD в Яндекс 360.
От: Sinclair Россия https://github.com/evilguest/
Дата: 11.02.26 09:46
Оценка:
Здравствуйте, Sharov, Вы писали:


S>Это почему? Я заранее не знаю из чего состоит автомобиль и как каждая его часть задействована в езде?

Я же дал вам список примеров. Что именно в них непонятно?
S>Каким образом?
Именно таким. В первой версии колёсам не надо было знать, куда мы поворачиваем, а во второй — надо.

S>Почему придется перекладывать, будут соотв. абстракции, которые будут отвечать за тот или иной аспект. Что и куда перекладывается?

Я же привёл примеры. Попробуйте прикинуть, какие сигнатуры будут у ваших классов для описания автомобиля.

S>Примеры с обратной кинематикой и способы решения диффуров? Это какие-то очень низкоуровневые детали.

Примеры с автомобилем. Мне не жалко, я ещё раз их приведу:

Дальше вы начинаете вызывать методы "Ехать влево" у составляющих агрегат элементов. Вот вы заложились на то, что у руля этот метод нужно вызывать, а у колёс и двигателя — нет.
Завтра к вам приходит заказчик и рассказывает, что в его модели автомобиля задние колёса умеют подруливать, поэтому им тоже нужно "знать" о повороте всего автомобиля влевою
А послезавтра он говорит, что теперь эти колёса должны подруливать интеллектуально — при перестроениях между полосами они должны подруливать в ту же сторону, а при манёврах в ограниченном пространстве в противоположную.
Ещё через неделю выясняется, что нужно контролировать занос — и при потере сцепления с дорогой (о чём "знают" только колёса, да и то при сравнении их данных друг с другом, а не по отдельности) нужно сбрасывать газ на двигателе.
И каждый раз, как поступает новое требование, вам приходится править всю иерархию классов, причём как интерфейс, так и реализацию.


S>Пускай. У кого будет не десяток, а сотня абстракций. Главное, что все они спрятаны за абстракцией Car.

Нет конечно. Нет такой абстракции "Car". Она тут совершенно не нужна. Есть "кинематическая схема", и она никакая не абстрактная, а совершенно конкретная. У неё нет никакого "поведения" в смысле ООП.
Если вам завтра надо будет решать задачу управления катером, а не автомобилем — вы что, будете с нуля писать новую абстракцию Boat?
А зачем? Чем эта абстракция будет отличаться от абстракции Car? Ладно, пусть там будет не Car/Boat, а абстракция Vehicle. Нужны ли будут для кинематики катера и автомобиля классы Boat:Vehicle и Car:Vehicle?
Если да, то зачем?

S>Техническое за Car, может бензина нет или другая поломка. Во всех остальных случаях -- зависит от контекста. Может документов каких нету?

Это не ответ. Сможем ли мы повторно использовать "абстракцию Car" во всех трёх доменах, или придётся всякий раз писать её заново?
Сможем ли мы реализовать в одном конкретном "классе SpecificCar" все три абстракции?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[42]: Как внедряли DDD в Яндекс 360.
От: Miroff Россия  
Дата: 11.02.26 11:30
Оценка: -1
Здравствуйте, Sinclair, Вы писали:

S>Вот это нужно как-то обосновывать. Потому, что связи не являются "свойствами" в каком-то объективном смысле — они не "принадлежат" сущности.


Здесь нет связей, здесь есть именно свойства сущностей.

S>Вот у нас есть отдел, есть его начальник. "Руководить" — это связь между отделом и сотрудником; она является "свойством" сотрудника в той же степени, что и отдела.


Это не связь, а совершенно отдельный доменный объект — "роль". У сотрудника может быть много ролей в одном отделе, эти роли могут пересекаться или активироваться по каким-то особым критериям. Вплоть до того, что роль может быть вакантной.

S>Поэтому и непонятно, отчего вы решили, что обязательство — это "свойство" единицы товара, что бы понятие "единица товара" ни означало.


Единица товара это атомарный субъект транзакции учета: пачка молока, красная шляпа, автомобиль. Ведь в реальности ты продаешь покупателю не -1 из строчки количество красных шляп, а конкретный предмет со собственными свойствами и историй. И при наступлении опредленного этапа жизненного цикла заказа у тебя появляется обязательство этот предмет выделить из кучи однотипных и передать его в пользование покупателю.

S>Это понятно. Непонятно, почему вы "поведение" приписываете каким-то конкретным концептам из вашего "домена".


Потому что поведение выражается через свойства доменных сущностей. Поведения в отрыве от сущностей не существует. Т.е. первичный сущности и только относительно сущностей мы можем определять поведение.

S>В домене "торговля товаром" обязательство является свойством контрагента, а не какого-то конкретного товара. Это не товар "перемещается" от поставщика к получателю, это кто-то, обладающий свободой воли, перемещает товар.


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

S>Так не бывает. Дизайн очень сильно влияет на реализацию, ни о какой ортогональности речь идти не может.


Реализация МОЖЕТ влиять на дизайн, но задача DDD это как раз избежать этого влияния моделируя предметную область в отрыве от искуственных ограничений. Ты можешь сделать дизайн чтобы самые частые операции выполнялись быстрее всего. Например сложить товары и заказы в одну базу. Но такой дизайн всегда получается очень хрупким, непригодным к расширению домена и при изменении требований такой дизайн быстро разваливающийся под собственной тяжестью.

К тому же, в современных системах не принято при выполнении доменной операции сразу бежать и что-то менять в хранилищах. Вместо этого операции накапливаются, а потом материализуются пачкой. Это могут транзакции в БД, CQRS,
функциональные эффекты или старый добрый паттерн Команда из GoF. Тебе никто не мешает в момент материализации переопределить порядок операций и применить любые мыслимые оптимизации, на которые у тебя хватит фантазии. Например, заменять пару SELECT/UPDATE на in place update или вообще на вызов хранимой процедуры которая генерируется из того же DSL

Атомарность заказа это на самом деле плохое требование. Оно сложное в реализации, плохо влияет на производительноть и, главное, не приносит прибыли маскируя проблему. Если мы не продали что-то потому что оно закончилось у нас на складе, это прямой УБЫТОК, потому что мы упустили прибыль. И современные системы строятся так, чтобы такое происходило как можно реже. Поэтому в приоритете динамической ценообразование, предсказание продаж, автоматическое пополнение и другие продвинутые процессы. В тех редких случаях когда такая ситуация произошла, дешевле вернуть покупателю деньги за недоставленный товар чем закладываться на этот сценарий.

S>Нет, это не проекция. То, что вы описываете — это REST-идеология, когда все сценарии выражаются в терминах CRUD-операций. Но она сама по себе работает только тогда, когда у нас нет никакого "поведения" за пределами этих модификаций.


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

S>Вот я взял и добавил связь между сотрудником и департаментом — и это привело к определённому результату, независимо от того, оформил ли я это через department.Employees += e или через e.Deparment = department. А может, так вообще нельзя, и нужно создать экземпляр EmployeeContractAddendum, который после подписания обеими сторонами автоматически отразит изменения штатного расписания департамента и должности у сотрудника.


Не всегда проекция возможна, это верно. Но ты и сам разрешил это противоречие добавив новую сущность.
Re[43]: Как внедряли DDD в Яндекс 360.
От: Sinclair Россия https://github.com/evilguest/
Дата: 11.02.26 17:05
Оценка:
Здравствуйте, Miroff, Вы писали:

M>Здесь нет связей, здесь есть именно свойства сущностей.

Непонятно. Сущность не может быть свойством другой сущности.

M>Это не связь, а совершенно отдельный доменный объект — "роль". У сотрудника может быть много ролей в одном отделе, эти роли могут пересекаться или активироваться по каким-то особым критериям. Вплоть до того, что роль может быть вакантной.

Этот объект совершенно точно не может быть отдельным. Потому что без сотрудника он невозможен, как и без отдела. Можно усложнять доменную модель, которую я предложил — например, так, как предложили вы.
Просто тогда в модели вместо бинарной связи "быть начальником" между сотрудником и отделом появляется тернарная связь "исполнять роль", в которой участвуют отдел, сотрудник, и роль.

M>Единица товара это атомарный субъект транзакции учета: пачка молока, красная шляпа, автомобиль. Ведь в реальности ты продаешь покупателю не -1 из строчки количество красных шляп, а конкретный предмет со собственными свойствами и историй. И при наступлении опредленного этапа жизненного цикла заказа у тебя появляется обязательство этот предмет выделить из кучи однотипных и передать его в пользование покупателю.

Это не означает, что я обязан держать где-то столько строчек, сколько есть экземпляров однотипных товаров у меня на складе.
Вот например, я продаю кому-то 0.435 кг изюма. Что такое "обязательство"? Что тут будет "предметом, выделяемым из кучи однотипных"? 1380 изюминок?

M>Потому что поведение выражается через свойства доменных сущностей. Поведения в отрыве от сущностей не существует. Т.е. первичный сущности и только относительно сущностей мы можем определять поведение.

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

M>В домене торговля никого "обладающего свободой" нет и быть не может. В торговле царствуют алгоритмы имеющие силу закона. Ты не можешь взять товар и переместить его вместо покупателя на свалку просто потому что тебе так захотелось.

Чего это вдруг? Запросто перемещу. Для этого мне достаточно оформить накладную на списание. И какое там "поведение" у этого товара мне наплевать — процесс списания регламентируется приказом по компании, и сегодня он один, завтра другой, а послезавтра он зависит от цвета шляпы. Бежать внедрять код логики списания внутрь класса, объектом которого является "красная шляпа" — это последнее, что стоит делать. Именно по этой причине.

M>Реализация МОЖЕТ влиять на дизайн, но задача DDD это как раз избежать этого влияния моделируя предметную область в отрыве от искуственных ограничений. Ты можешь сделать дизайн чтобы самые частые операции выполнялись быстрее всего. Например сложить товары и заказы в одну базу. Но такой дизайн всегда получается очень хрупким, непригодным к расширению домена и при изменении требований такой дизайн быстро разваливающийся под собственной тяжестью.



M>К тому же, в современных системах не принято при выполнении доменной операции сразу бежать и что-то менять в хранилищах. Вместо этого операции накапливаются, а потом материализуются пачкой. Это могут транзакции в БД, CQRS,

M>функциональные эффекты или старый добрый паттерн Команда из GoF. Тебе никто не мешает в момент материализации переопределить порядок операций и применить любые мыслимые оптимизации, на которые у тебя хватит фантазии. Например, заменять пару SELECT/UPDATE на in place update или вообще на вызов хранимой процедуры которая генерируется из того же DSL


M>Атомарность заказа это на самом деле плохое требование. Оно сложное в реализации, плохо влияет на производительноть и, главное, не приносит прибыли маскируя проблему. Если мы не продали что-то потому что оно закончилось у нас на складе, это прямой УБЫТОК, потому что мы упустили прибыль. И современные системы строятся так, чтобы такое происходило как можно реже. Поэтому в приоритете динамической ценообразование, предсказание продаж, автоматическое пополнение и другие продвинутые процессы. В тех редких случаях когда такая ситуация произошла, дешевле вернуть покупателю деньги за недоставленный товар чем закладываться на этот сценарий.

Всё верно. Это означает, что подход, в котором "цена" является свойством "товара", непригоден. Даже если мы это свойство делаем вычисляемым. Сам товар не может знать, почём его продают — потому что ценообразование динамическое, и оно зависит и от товара, и от наличия этого товара на складе сейчас, и от покупателя и его предыстории, и от соседних товаров в том же заказе.
Никакая из этих "доменных сущностей" не подходит для размещения логики определения цены. Только какой-то внешний по отношению к этому домену "динамический ценообразователь", который, как правило, стейтлесс.
Вот он скорее всего будет построен по принципам ООП — там тебе и наследование, и полиморфизм, и агрегация, и паттерны Policy, и Factory Method и все лучшие наработки. А вот в "доменных сущностях" (в терминологии ER-модели) никакой логики не будет.

S>>Нет, это не проекция. То, что вы описываете — это REST-идеология, когда все сценарии выражаются в терминах CRUD-операций. Но она сама по себе работает только тогда, когда у нас нет никакого "поведения" за пределами этих модификаций.


M>Ну да, REST широко использует проекции данных. Это неудивительно, ведь все что мы делаем, в конечном итоге сводится к машине Тюринга на конечной ленте, а в ней ничего кроме данных не существует.


S>>Вот я взял и добавил связь между сотрудником и департаментом — и это привело к определённому результату, независимо от того, оформил ли я это через department.Employees += e или через e.Deparment = department. А может, так вообще нельзя, и нужно создать экземпляр EmployeeContractAddendum, который после подписания обеими сторонами автоматически отразит изменения штатного расписания департамента и должности у сотрудника.


M>Не всегда проекция возможна, это верно. Но ты и сам разрешил это противоречие добавив новую сущность.

То, что вы используете общепринятые термины в необщепринятом смысле, только затрудняет коммуникацию.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[43]: Как внедряли DDD в Яндекс 360.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 12.02.26 00:29
Оценка:
Здравствуйте, Miroff, Вы писали:

M>Атомарность заказа это на самом деле плохое требование. Оно сложное в реализации, плохо влияет на производительноть и, главное, не приносит прибыли маскируя проблему. Если мы не продали что-то потому что оно закончилось у нас на складе, это прямой УБЫТОК, потому что мы упустили прибыль. И современные системы строятся так, чтобы такое происходило как можно реже. Поэтому в приоритете динамической ценообразование, предсказание продаж, автоматическое пополнение и другие продвинутые процессы. В тех редких случаях когда такая ситуация произошла, дешевле вернуть покупателю деньги за недоставленный товар чем закладываться на этот сценарий.


Никогда не видел столько заблуждений в одной фразе.
Это же насколько надо не разбираться в:
— архитектуре ПО
— финансах
— маркетинге
— человеческой психологии
чтобы толкать такую чушь...
Re[44]: Как внедряли DDD в Яндекс 360.
От: Miroff Россия  
Дата: 12.02.26 01:54
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Никогда не видел столько заблуждений в одной фразе.

G>Это же насколько надо не разбираться в:
G>- архитектуре ПО
G>- финансах
G>- маркетинге
G>- человеческой психологии
G>чтобы толкать такую чушь...

Самшено слышать это от человека, у которого корзина обновляется транзакционно со складом
Re[44]: Как внедряли DDD в Яндекс 360.
От: Miroff Россия  
Дата: 12.02.26 03:25
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Непонятно. Сущность не может быть свойством другой сущности.


С чего бы? Колеса это свойство автомобиля в значении part of.

S>Этот объект совершенно точно не может быть отдельным. Потому что без сотрудника он невозможен, как и без отдела. Можно усложнять доменную модель, которую я предложил — например, так, как предложили вы.


Роль может существовать и без сотрудника и без отдела. Например, ТКРФ определяет роль "представитель профсоюза" необходимую для решения трудовых конфликтов. У тебя в компании может не быть ни профсоюза, ни сотрудников, но роль такая есть в силу закона. А из твоего утверждения следует, что раз в компании нет профсоюза, то и представителей профсоюза не бывает.

S>Просто тогда в модели вместо бинарной связи "быть начальником" между сотрудником и отделом появляется тернарная связь "исполнять роль", в которой участвуют отдел, сотрудник, и роль.


S>Это не означает, что я обязан держать где-то столько строчек, сколько есть экземпляров однотипных товаров у меня на складе.


Именно это и означает. Вам даже государство прямым текстом говорит через честный знак: ребята, надо переходить на поединичный учет. Пора уже, ну сколько можно?

S>Вот например, я продаю кому-то 0.435 кг изюма. Что такое "обязательство"? Что тут будет "предметом, выделяемым из кучи однотипных"? 1380 изюминок?


Это на самом деле операция производства: из единицы хранения ящик изюма ты выделяешь 435г в упаковку и эта упаковка становится новой товарной единицей.

S>Всё верно. Это означает, что подход, в котором "цена" является свойством "товара", непригоден. Даже если мы это свойство делаем вычисляемым. Сам товар не может знать, почём его продают — потому что ценообразование динамическое, и оно зависит и от товара, и от наличия этого товара на складе сейчас, и от покупателя и его предыстории, и от соседних товаров в том же заказе.

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

Именно! Если мы пересматриваем модель ценообразования, нам нужно глубоко анализировать домен, в котором эта цена вычисляется. Нас буквально ЗАСТАВЛЯЮТ отвечать на "неудобные" вопросы, вроде: из чего складывается цена? Каким образом она складывается? Различимы ли с точки зрения цены красная шляпа один, красная шляпа два и черная шляпа три? Должна ли история продаж лапсердаков влиять на цену красных шляп? Сама архитектура провоцирует глубокую аналитику и ресерч, а не просто копировать одни и те же таблички из проекта в проект.

S>То, что вы используете общепринятые термины в необщепринятом смысле, только затрудняет коммуникацию.


Очень трудно говорить с человеком, который ментально застрял где-то в 2006 году)

Я рекомендую тебе попробовать сделать какой-нибудь проект на принципиально новом для тебя стеке, например на Scala c CATS/ZIO. Там у тебя будут нормальные функциональные монады, множественное наследование, частичное наследование, богатая система типов, частичные вычисления и богата система типов. Такой опыт сильно расширит твой архитектурный кругозор пониманием, что вовсе не обязательно ограничиваться двумя отношениями is_a и part_of.

Я понимаю твою позицию, давайте сделаем анемичную модель и распихаем логику по сервисам. На практике это едва ли не худший подход, который можно себе представить Сервисная архитектура довольно быстро вырождается в уродливого неподдерживаемого монстра по нескольким причинам:

1. Сервисы не дают тебе обратной связи о том, что твоя доменная модель неадекватна реальности. Разработчики городят сервисы на сервисы и довольно быстро система теряет концептуальную целостность. Со временем это приводит к потере понимания системы и появлению типичных для этого класса архитектур багов неконсистентности на границах сервисов. В то время как с рич моделью невозможность засунуть метод в какой-то класс это однозначный сигнал что в той модели мира, на основе которой построена эта модель, данная операция невозможна и необходим рефакторинг. Причем рефакторинг должен заключаться в пересмотре модели мира, а в перекладывании методов между классами.

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

3. В силу п.2, иерархии сервисов не коррелируют с иерархиями доменной модели. Это приводит к тому, что сервисы изобилуют проверками сущностей, с которыми они взаимодействуют. Это еще один источник багов, прямо по Аллену. К тому же, это даже не ООП, а откат к процедурному программированию.
Re[45]: Как внедряли DDD в Яндекс 360.
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.02.26 06:55
Оценка:
Здравствуйте, Miroff, Вы писали:

M>С чего бы? Колеса это свойство автомобиля в значении part of.

По определению. Сущность — концепт предметной области, обладающий идентичностью и с независимым от других сущностей жизненным циклом.
В вашей метафоре колеса существуют совершенно отдельно от автомобиля — например, лежат на складе.
А когда мы их монтируем в автомобиль, то между автомобилем и колесом возникает связь "to be part of" / "to consist of".

M>Роль может существовать и без сотрудника и без отдела. Например, ТКРФ определяет роль "представитель профсоюза" необходимую для решения трудовых конфликтов.

В такой предметной области эта "роль" сущностью не является — у неё нет жизненного цикла. Она существует "вне времени".
В ER-модели она является атрибутом сотрудника, с двумя возможными значениями "да" и "нет".

M>Именно это и означает. Вам даже государство прямым текстом говорит через честный знак: ребята, надо переходить на поединичный учет. Пора уже, ну сколько можно?

Вы уже начали поединичный учёт зерён гречки и изюминок? Нет? Пора уже, ну сколько можно!

M>Это на самом деле операция производства: из единицы хранения ящик изюма ты выделяешь 435г в упаковку и эта упаковка становится новой товарной единицей.

Нет никакой упаковки, и никакой новой товарной единицы.
И чем "ящик изюма" так принципиально отличается от "ящика шляп" или "склада с цементом"?

M>Именно! Если мы пересматриваем модель ценообразования, нам нужно глубоко анализировать домен, в котором эта цена вычисляется. Нас буквально ЗАСТАВЛЯЮТ отвечать на "неудобные" вопросы, вроде: из чего складывается цена? Каким образом она складывается? Различимы ли с точки зрения цены красная шляпа один, красная шляпа два и черная шляпа три? Должна ли история продаж лапсердаков влиять на цену красных шляп? Сама архитектура провоцирует глубокую аналитику и ресерч, а не просто копировать одни и те же таблички из проекта в проект.

Всё верно. При этом DDD нам тут только мешает, т.к. требует вносить эту логику манипулирования сущностями внутрь самих этих сущностей.

M>Очень трудно говорить с человеком, который ментально застрял где-то в 2006 году)

Я с радостью выйду из 2006 года, если вы мне дадите ссылку на какую-нибудь литературу, которая систематически излагает "более новую" модель, которой вы оперируете.

M>Я рекомендую тебе попробовать сделать какой-нибудь проект на принципиально новом для тебя стеке, например на Scala c CATS/ZIO. Там у тебя будут нормальные функциональные монады, множественное наследование, частичное наследование, богатая система типов, частичные вычисления и богата система типов. Такой опыт сильно расширит твой архитектурный кругозор пониманием, что вовсе не обязательно ограничиваться двумя отношениями is_a и part_of.

Я придерживаюсь той точки зрения, что стек — вторичен. Первична именно архитектура. Не имеет никакого смысла изучать особенности какого-то конкретного фреймворка, не понимая первооснов.
Например, модель Чена, придуманная ажно в 1975 году, популярна как раз в силу своей агностики по отношению к выбранной технологии. Поэтому можно брать её за основу, а уже потом переходить от концептуальной модели к какой-нибудь логической — например, к реляционной, или объектной, или функциональной.
Кстати, функциональная модель обычно навязывает гораздо более качественную архитектуру, чем лобовое DDD. Потому что в ней манипуляции (функции) отделены от состояния (данных).
Когда мы применяем этот подход к проектированию бизнес-софта с использованием ООП, возникает т.н. "анемик модель", в которой объекты делятся на две несимметричные группы: "сущности", у которых нет поведения, и "обработчики", у которых нет состояния.

M>Я понимаю твою позицию, давайте сделаем анемичную модель и распихаем логику по сервисам. На практике это едва ли не худший подход, который можно себе представить Сервисная архитектура довольно быстро вырождается в уродливого неподдерживаемого монстра по нескольким причинам.

Причины хорошие, но они остаются, скажем так, абстрактными рассуждениями без реального кода.
Вот вы предложили скалу с каким-то фреймворком — ок, давайте рассмотрим, как выглядит в ней решение какой-нибудь типовой задачи. Да хоть с теми же заказами, товарами, покупателями, оплатами и отгрузками.
Эта задача хороша тем, что она подробно задокументирована, например — в спецификации тестов TPC-C.
Решение в стиле 90х для неё есть — там где адский SQL с его хранимками.
Как будет выглядеть её решение в каноническом DDD на Java мы тоже знаем (и понимаем, почему оно превращается в неподдерживаемого монстра, который работает в 100 раз медленнее, чем решение на устаревших технологиях).
Как будет выглядеть модное решение? Ну, хотя бы его фрагмент?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[45]: Как внедряли DDD в Яндекс 360.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 12.02.26 08:03
Оценка:
Здравствуйте, Miroff, Вы писали:

M>Здравствуйте, gandjustas, Вы писали:


G>>Никогда не видел столько заблуждений в одной фразе.

G>>Это же насколько надо не разбираться в:
G>>- архитектуре ПО
G>>- финансах
G>>- маркетинге
G>>- человеческой психологии
G>>чтобы толкать такую чушь...

M>Самшено слышать это от человека, у которого корзина обновляется транзакционно со складом

А вы тоже можете (нет) привести пример кода как это сделать лучше?
Re[48]: Как внедряли DDD в Яндекс 360.
От: Sharov Россия  
Дата: 15.02.26 13:57
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>>Примеры с обратной кинематикой и способы решения диффуров? Это какие-то очень низкоуровневые детали.

S>Примеры с автомобилем. Мне не жалко, я ещё раз их приведу:
S>

S>Дальше вы начинаете вызывать методы "Ехать влево" у составляющих агрегат элементов. Вот вы заложились на то, что у руля этот метод нужно вызывать, а у колёс и двигателя — нет.
S>Завтра к вам приходит заказчик и рассказывает, что в его модели автомобиля задние колёса умеют подруливать, поэтому им тоже нужно "знать" о повороте всего автомобиля влевою
S>А послезавтра он говорит, что теперь эти колёса должны подруливать интеллектуально — при перестроениях между полосами они должны подруливать в ту же сторону, а при манёврах в ограниченном пространстве в противоположную.
S>Ещё через неделю выясняется, что нужно контролировать занос — и при потере сцепления с дорогой (о чём "знают" только колёса, да и то при сравнении их данных друг с другом, а не по отдельности) нужно сбрасывать газ на двигателе.
S>И каждый раз, как поступает новое требование, вам приходится править всю иерархию классов, причём как интерфейс, так и реализацию.


Почему всю-то сразу, добавляем новую реализацию соотв. интерфейса. Автомобиль грубо можно поделить на 3 части -- кузов, двигатель и шасси(ходовая).
Каждый является в свою очередь модулем, состоящим из более мелких деталей. Соотв. изменения будут только в этом соотв. модуле, могут
быть несколько реализаций колес, например. По отдельности собираем каждый модуль и передаем все в конструктор машины. Расширения будут,
но всегда локализовано.

Короче, если я вас правильно понял, то вы хотите, чтобы абстракция Car была максимально простой и буквально реализовывала метод "consist of",
а вся сложность за отдельные "виды деятельности" переехала бы в соотв. классы (кинематическая модель и т.п.), верно? Т.е. некоторые
абстракции, которые бы на вход получали только Car. Если так, то мне не нравится этот подход размазыванием логики по нескольким модулям.
Это, кмк, очень на процедурный стиль похоже. Я бы все-таки все эти детали прятал бы под абстракцией Car и добавлял бы в соотв. интерфейс
только необходимые высокоуровневые методы, типа move\drive. Да, была бы большая и сложная абстракция Car, зато все как-то локализовано и похоже
на моделируемый внешний мир.

S>>Пускай. У кого будет не десяток, а сотня абстракций. Главное, что все они спрятаны за абстракцией Car.

S>Нет конечно. Нет такой абстракции "Car". Она тут совершенно не нужна. Есть "кинематическая схема", и она никакая не абстрактная, а совершенно конкретная. У неё нет никакого "поведения" в смысле ООП.

Ну как нет-то, если в реальном мире есть "Car", а в модели почему-то не нужен?

S>Если вам завтра надо будет решать задачу управления катером, а не автомобилем — вы что, будете с нуля писать новую абстракцию Boat?

S>А зачем? Чем эта абстракция будет отличаться от абстракции Car? Ладно, пусть там будет не Car/Boat, а абстракция Vehicle. Нужны ли будут для кинематики катера и автомобиля классы Boat:Vehicle и Car:Vehicle?

Средой движения будет отличаться, как минимум физикой движения и соотв. законами и параметрами. Общее, вроде двигателей, тоже будет.
Но как-то полиморфно работать и с машиной и с катером... ну такое.

S>Если да, то зачем?


Не глядя на код этой кинематики, трудно представить, чтобы она единообразно отвечала за движения и автомобиля и катера. Уж больно
они разные. Т.е. что-то такое можно сделать, но это будет нечто высокоуровневое и простое, а вся сложность уедет в соотв. реализацию
Vehicle. Собственно, я за такой подход и ратую. А нужно тогда будет отдельная кинематическая модель, если вся сложность будет
инкапсулирована в Vehicle, может в интерфейс Vehicle добавить методов и все?


S>>Техническое за Car, может бензина нет или другая поломка. Во всех остальных случаях -- зависит от контекста. Может документов каких нету?

S>Это не ответ. Сможем ли мы повторно использовать "абстракцию Car" во всех трёх доменах, или придётся всякий раз писать её заново?
S>Сможем ли мы реализовать в одном конкретном "классе SpecificCar" все три абстракции?

На сколько я понимаю ДДД + здравый смысл мне говорит, что нет, для каждого домена должны быть своя особенная Car. Для Car, которая умеет двигаться,
зачем ей уметь работать со всякими регистрациями и т.п.? Там сильно своя специфика. Т.е. должны быть 3 разных Car, но их инстансы должны шарить\иметь
какой-то общий id, чтобы можно было понять, что речь идет об одном и том же автомобиле, но в разных доменах.
Кодом людям нужно помогать!
Re[49]: Как внедряли DDD в Яндекс 360.
От: Sinclair Россия https://github.com/evilguest/
Дата: 16.02.26 01:45
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Почему всю-то сразу, добавляем новую реализацию соотв. интерфейса.

Потому что в соотв. интерфейсе у вас исходно не было метода "ехать влево". Вы же полагали, что он нужен только рулю.

S>Автомобиль грубо можно поделить на 3 части -- кузов, двигатель и шасси(ходовая).

S>Каждый является в свою очередь модулем, состоящим из более мелких деталей. Соотв. изменения будут только в этом соотв. модуле, могут
S>быть несколько реализаций колес, например. По отдельности собираем каждый модуль и передаем все в конструктор машины. Расширения будут,
S>но всегда локализовано.
Смотрите, дело не в изменениях реализаций. Дело в том, что приходится вносить изменения в интерфейс, т.к. поведение не локализовано.
В итоге вы заканчиваете тем, что кузов, двигатель, и шасси реализуют ровно один и тот же интерфейс, в котором реализован полный набор всех методов, которые умеет делать автомобиль.

S>Короче, если я вас правильно понял, то вы хотите, чтобы абстракция Car была максимально простой и буквально реализовывала метод "consist of",

S>а вся сложность за отдельные "виды деятельности" переехала бы в соотв. классы (кинематическая модель и т.п.), верно?
Это не я хочу, это вам придётся так сделать. И в итоге продуктивнее окажется вообще отказаться от абстракции Car, потому что она ничем-ничем не отличается от абстракции Helicopter.
Более того, абстракция "Шасси" в вашем Car тоже реализует ровно тот же интерфейс, что и абстракции Helicopter и Car. Это интерфейс CompositeModel.

S>Т.е. некоторые абстракции, которые бы на вход получали только Car. Если так, то мне не нравится этот подход размазыванием логики по нескольким модулям.

Это у вас пока не наработана архитектурная интуиция. Не "размазывание", а концентрация. Tight cohesion, low coupling. Кинематическая логика сосредоточена в модуле кинематики, который никак не завязан на автомобильность.
Логика ценообразования — в модуле ценообразования, который опять никак не завязан на торговлю именно автомобилями.
При этом у нас нет смешивания логики кинематики (которая описывает физический мир, и потому неизменна) с логикой ценообразования (которая может меняться ежеквартально).

S>Это, кмк, очень на процедурный стиль похоже. Я бы все-таки все эти детали прятал бы под абстракцией Car и добавлял бы в соотв. интерфейс

S>только необходимые высокоуровневые методы, типа move\drive. Да, была бы большая и сложная абстракция Car, зато все как-то локализовано и похоже
S>на моделируемый внешний мир.
Ну потому что вас так воспитали дурацкие книжки. Вы усердно хотите написать большой, сложный, плохо поддерживаемый код, под тем предлогом, что он чем-то там похож на реальный мир.
Нет, в реальном мире всё работает не так, как в ООП.

S>Ну как нет-то, если в реальном мире есть "Car", а в модели почему-то не нужен?

Это иллюзия, а не Car. В реальном мире есть какое-нибудь "основное средство", в котором от автомобиля нет примерно никаких особенностей. Более того, поведение основных средств зависит не от этих средств, а от учётной политики.

S>Не глядя на код этой кинематики, трудно представить, чтобы она единообразно отвечала за движения и автомобиля и катера. Уж больно

S>они разные. Т.е. что-то такое можно сделать, но это будет нечто высокоуровневое и простое, а вся сложность уедет в соотв. реализацию
S>Vehicle. Собственно, я за такой подход и ратую. А нужно тогда будет отдельная кинематическая модель, если вся сложность будет
S>инкапсулирована в Vehicle, может в интерфейс Vehicle добавить методов и все?
Нет. Вся сложность будет реализована в движке расчёта физики. Потому что физика — она одна на всех.

S>На сколько я понимаю ДДД + здравый смысл мне говорит, что нет, для каждого домена должны быть своя особенная Car. Для Car, которая умеет двигаться,

S>зачем ей уметь работать со всякими регистрациями и т.п.? Там сильно своя специфика. Т.е. должны быть 3 разных Car, но их инстансы должны шарить\иметь
S>какой-то общий id, чтобы можно было понять, что речь идет об одном и том же автомобиле, но в разных доменах.
А то. И общее устройство — потому что если в одном из этих Car смонтирован двигатель, то и в двух других тот же двигатель.
Так мы и приходим к абстракции Car как plain data object.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[50]: Как внедряли DDD в Яндекс 360.
От: Sharov Россия  
Дата: 17.02.26 23:32
Оценка:
Здравствуйте, Sinclair, Вы писали:


S>>Автомобиль грубо можно поделить на 3 части -- кузов, двигатель и шасси(ходовая).

S>>Каждый является в свою очередь модулем, состоящим из более мелких деталей. Соотв. изменения будут только в этом соотв. модуле, могут
S>>быть несколько реализаций колес, например. По отдельности собираем каждый модуль и передаем все в конструктор машины. Расширения будут,
S>>но всегда локализовано.
S>Смотрите, дело не в изменениях реализаций. Дело в том, что приходится вносить изменения в интерфейс, т.к. поведение не локализовано.
S>В итоге вы заканчиваете тем, что кузов, двигатель, и шасси реализуют ровно один и тот же интерфейс, в котором реализован полный набор всех методов, которые умеет делать автомобиль.

Почему? У меня три независимых модуля, которые взаимодействуют определенным образом. Да, надо добавить метод "ехать влево", но добавлен он будет
только верхнеуровневой абстракции (Car) и модулю ходовой. Кузов и двигатель тут не при делах. Все-таки какая-то функциональная изоляция должна быть.
Автомобиль "ехать влево" будет дергать только у ходовой.

S>>Короче, если я вас правильно понял, то вы хотите, чтобы абстракция Car была максимально простой и буквально реализовывала метод "consist of",

S>>а вся сложность за отдельные "виды деятельности" переехала бы в соотв. классы (кинематическая модель и т.п.), верно?
S>Это не я хочу, это вам придётся так сделать. И в итоге продуктивнее окажется вообще отказаться от абстракции Car, потому что она ничем-ничем не отличается от абстракции Helicopter.
S>Более того, абстракция "Шасси" в вашем Car тоже реализует ровно тот же интерфейс, что и абстракции Helicopter и Car. Это интерфейс CompositeModel.

У меня совершенно не было идеи использовать паттерн композит, хотя понятно, откуда откуда у двигателя может появиться метод "ехать влево".
Совершенно обычная агрегация автомобилем других классов, типа:
class Car
{
class carcase;
class engine;
class chassis
}

Данные модули будут взаимодействовать по определенным интерфейсам, возможно через другие абстракции. Но суть в том, что они изолированы и мало имеют общего.


S>>Т.е. некоторые абстракции, которые бы на вход получали только Car. Если так, то мне не нравится этот подход размазыванием логики по нескольким модулям.

S>Это у вас пока не наработана архитектурная интуиция. Не "размазывание", а концентрация. Tight cohesion, low coupling. Кинематическая логика сосредоточена в модуле кинематики, который никак не завязан на автомобильность.

Это очень спорный факт, что на автомобильность не завязано. Потому как мне кажется, тут будет ровно наоборот -- low cohesion, high coupling.
Вместо того, чтобы все что связано с автомобилем максимально убрать в автомобиль, в том числе соотв. физ. модели. Это и будет high cohesion, low coupling.

S>Логика ценообразования — в модуле ценообразования, который опять никак не завязан на торговлю именно автомобилями.

S>При этом у нас нет смешивания логики кинематики (которая описывает физический мир, и потому неизменна) с логикой ценообразования (которая может меняться ежеквартально).

Ну да, а я и не предлагал тащить в ценообразование Car, туда надо тащить CarProxy какой-то.

S>>Это, кмк, очень на процедурный стиль похоже. Я бы все-таки все эти детали прятал бы под абстракцией Car и добавлял бы в соотв. интерфейс

S>>только необходимые высокоуровневые методы, типа move\drive. Да, была бы большая и сложная абстракция Car, зато все как-то локализовано и похоже
S>>на моделируемый внешний мир.
S>Ну потому что вас так воспитали дурацкие книжки. Вы усердно хотите написать большой, сложный, плохо поддерживаемый код, под тем предлогом, что он чем-то там похож на реальный мир.

Я хочу именно, как выше верно добавлено в дискуссию, "high cohesion, low coupling". Вот именно это. Надо было раньше об этом написать.

S>Нет, в реальном мире всё работает не так, как в ООП.


Мы решаем проблемы реального мира или ООП?

S>>Не глядя на код этой кинематики, трудно представить, чтобы она единообразно отвечала за движения и автомобиля и катера. Уж больно

S>>они разные. Т.е. что-то такое можно сделать, но это будет нечто высокоуровневое и простое, а вся сложность уедет в соотв. реализацию
S>>Vehicle. Собственно, я за такой подход и ратую. А нужно тогда будет отдельная кинематическая модель, если вся сложность будет
S>>инкапсулирована в Vehicle, может в интерфейс Vehicle добавить методов и все?
S>Нет. Вся сложность будет реализована в движке расчёта физики. Потому что физика — она одна на всех.

Ну не верю я, что физика не будет учитывать особенности движения и строения вертолета и машины или лодки. Это совершенно разные физ. области(домены).

S>>На сколько я понимаю ДДД + здравый смысл мне говорит, что нет, для каждого домена должны быть своя особенная Car. Для Car, которая умеет двигаться,

S>>зачем ей уметь работать со всякими регистрациями и т.п.? Там сильно своя специфика. Т.е. должны быть 3 разных Car, но их инстансы должны шарить\иметь
S>>какой-то общий id, чтобы можно было понять, что речь идет об одном и том же автомобиле, но в разных доменах.
S>А то. И общее устройство — потому что если в одном из этих Car смонтирован двигатель, то и в двух других тот же двигатель.
S>Так мы и приходим к абстракции Car как plain data object.

Я не согласен. У нас есть модель физ. автомобиля и его прокси для соотв. доменов. Они шарят что-то общее, чтобы понять, что речь о конкретном автомобиле,
но не более.
Кодом людям нужно помогать!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.