Search
Write a publication
Pull to refresh
0
0
Pavel Voronin @voroninp

User

Send message

Да я просто устал объяснять коллегам, что тянуть голый DbContext, обосновывая тем, что он, якобы уже репа, сомнительная идея.

При этом они настойчиво мокают IQueryable и DbSet в тестах. Уж лучше тогда интеграционные тесты с TestContainers гонять, чем тестировать моки:-)

Так автор вроде и говорит, что не надо его наружу выставлять, чтоб абы кто мог его теребонькать.

И да, я бы на первое место всё-таки ставил агрегат, а репозиторий — это его скромный слуга.
И главный акцент на поведении. Моделировать поведение, состояние будет производной. Беда EF в том, что люди сразу мыслят ДТОхами, замапленными на таблицы.

За DbContext отдельное спасибо.

Кстати, я все-таки делаю базовый класс, который эксёпшены EFCore'а переделывает в доменные ошибки, помимо FindById еще выставляю ListByIds и ListAll потому что на практике иногда удобно забить на масштабируемость и фигачить батчи с агрегатами в одной транзакции.

Entity — это нечто, обладающее идентичностью и позволяющее различать объекты (не в ООП смысле), все остальные атрибуты которых одинаковы. Какой доменный концепт обладает идентичностью, зависит уже от бизнеса.

Эванс делает акцент на жизненном цикле и существовании во времени.

Доменное событие может и асинхронно обрабатываться, аналогично integration event, главное, чтоб без пересечения границ контекста.

Так это... Aggregates and Repositories are relevant for C part of CQRS.

Кверики для UI вполне могут формировать представления, объединяющие лютые проекции 100500 агрегатов. Вам же в этом случае инварианты проверять и обеспечивать не требуется, так как нет изменения состояния.

Ты не задеваешь, ты просто пишешь много букв без конкретики и додумваешь в своей голове.

Как ты собираешься менять состояние не абы где и как, а в рамках ограниченного скоупа? В любимом тобой ООП этот скоуп определяется классом.

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

Народ, собсно, просит более явный способ группировки.

https://github.com/golang/go/issues/55863

А теперь давай покажи, где ты в моем ткомментарии увидел про VO?

Цель построить здание, подцель — соединить конструкции. Строили и без гвоздей. ;-) Бизнесу нужно ехать, шашечки его не сильно волнуют.

Критерий Эванс предлагает следующий: continuity у entity и концептуальная неотличимость двух объектов с одинаковыми атрибутами у VO.

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

Эванс во многом опирается на Фаулера и GoF, но вообще там местами есть тонкие отличия, потому как у Эванса рассуждения больше про предметную модель, нежели про техническую реализацию.

Инкапсуляция — это тоже инструмент, хотя и приятный. :-)

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

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

Вот комментарий Вернона: https://github.com/VaughnVernon/IDDD_Samples/issues/22

Вот выдержка из книги Эванса:

Creating extra options for performance tuning can be important because VALUE OBJECTS tend to be numerous. The example of the house design software hints at this. If each electrical outlet is a separate VALUE OBJECT, there might be a hundred of them in a single version of a single house plan. But if all outlets are considered interchangeable, we could share just one instance of an outlet and point to it a hundred times (an example of FLYWEIGHT [Gamma et al. 1995]). In large systems, this kind of effect can be multiplied by thousands, and such an optimization can make the difference between a usable system and one that slows to a crawl, choked on millions of redundant objects. This is just one example of an optimization trick that is not available for ENTITIES. The economy of copying versus sharing depends on the implementation environment. Although copies may clog the system with huge numbers of objects, sharing can slow down a distributed system. When a copy is passed between two machines, a single message is sent and the copy lives independently on the receiving machine. But if a single instance is being shared, only a reference is passed, requiring a message back to the object for each interaction. Sharing is best restricted to those cases in which it is most valuable and least troublesome:
• When saving space or object count in the database is critical
• When communication overhead is low (such as in a centralized server)
• When the shared object is strictly immutable

Например, в определенных случаях может существовать таблица VO где есть синтетический PK и Unique Index по всем значимым атрибутам. И гонять будут только PK между системами. Важно лишь то, что в контексте бизнес-модели у такого объекта не существует identity. Она здесь вылезает не более в качестве технического решения.

Ну успешного вам хранения коллекции VO в ентити без использования json columns. Это как минимум.

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

Только тактическая часть, и то не всё. ООП не более чем инструмент.

Практически любой успешный/долго живущий софт неизбежно обрастает разного рода нюансами. Проблема часто не столько даже в когнитивной сложности, сколько в неочевидном маппинге problem->solution.

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

Я к тому, что стратегическая часть DDD очень желательна с самого начала проекта, но разве будет менеджмент читать синюю книгу... И тем она и полезна для инженеров, чтоб осознать тщетность технических потуг, если идея не "продана" бизнесу.

Легко

Domain Modeling Made Functional: Tackle Software Complexity with Domain-Driven Design and F# by Scott Wlaschin

https://pragprog.com/titles/swdddf/domain-modeling-made-functional/

Тут надо понимать, что Identity на уровне домена не есть Identity на уровне БД.

И иногда действительно может иметь смысл воткнуть PK в VO, но он, очевидно, никак не должен участвовать в equality.

1

Information

Rating
11,649-th
Location
Amstelveen, Noord-Holland, Нидерланды
Date of birth
Registered
Activity

Specialization

Backend Developer, Software Architect
Senior