Лучшие практики для сериализации DDD агрегатов

23

Согласно DDD логика домена не должна быть загрязнена техническими проблемами, такими как сериализация, объектно-реляционное отображение и т. Д.

Так как же сериализовать или отобразить состояние агрегатов, не раскрывая его публично через геттеры и сеттеры? Я видел множество примеров, например, для реализации репозитория, но практически все они полагались на общедоступные методы доступа к объектам и объектам значений для отображения.

Мы могли бы использовать рефлексию, чтобы избежать открытых средств доступа, но IMO эти доменные объекты все равно будут неявно зависеть от проблемы сериализации. Например, вы не можете переименовать или удалить приватное поле без настройки конфигурации сериализации / сопоставления. Таким образом, вы должны рассмотреть сериализацию, где вам следует сосредоточиться на доменной логике.

Так какой же самый лучший компромисс здесь? Жить с общедоступными средствами доступа, но избегать их использования для чего-либо еще, кроме отображения кода? Или я просто упустил что-то очевидное?

Я явно заинтересован в сериализации состояния объектов домена DDD (агрегатов, состоящих из сущностей и объектов-значений). Это НЕ касается сериализации в общем случае или сценариев сценариев транскрипции, когда службы без сохранения состояния работают с простыми объектами контейнера данных.

EagleBeak
источник

Ответы:

12

Виды предметов

Для целей нашего обсуждения давайте разделим наши объекты на три различных вида:

Бизнес-логика

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

Объектные логические объекты обычно не требуют доступа (геттеры и сеттеры). Скорее, вы создаете объект, передавая ему зависимости через конструктор, а затем управляете объектом с помощью методов (скажите, не спрашивайте).

Объекты передачи данных

Объекты передачи данных находятся в чистом виде; они не содержат никакой бизнес-логики. У них всегда будут аксессуары. Они могут иметь или не иметь сеттеры, в зависимости от того, пишете ли вы их неизменным образом. Вы либо установите свои поля в конструкторе, и их значения не будут меняться в течение всего времени существования объекта, либо ваши методы доступа будут доступны для чтения / записи. На практике эти объекты обычно являются изменяемыми, поэтому пользователь может их редактировать.

Просмотр объектов модели

Объекты View Model содержат отображаемое / редактируемое представление данных. Они могут содержать бизнес-логику, обычно ограниченную проверкой данных. Примером объекта View Model может быть InvoiceViewModel, содержащий объект Customer, объект заголовка Invoice и отдельные позиции Invoice. Объекты View Model всегда содержат методы доступа.

Таким образом, единственным видом объекта, который будет «чистым» в том смысле, что он не содержит полевых методов доступа, будет объект логики домена. Сериализация такого объекта сохраняет его текущее «вычислительное состояние», так что его можно извлечь позже для завершения обработки. Модели представлений и DTO можно свободно сериализовать, но на практике их данные обычно сохраняются в базе данных.

Сериализация, зависимости и связь

Несмотря на то, что сериализация создает зависимости, в том смысле, что вам необходимо десериализовать совместимый объект, это не обязательно означает, что вы должны изменить конфигурацию сериализации. Хорошие механизмы сериализации имеют общее назначение; им все равно, если вы измените имя свойства или члена, если оно все еще может отображать значения для членов. На практике это означает, что вы должны повторно сериализовать экземпляр объекта, чтобы представление сериализации (xml, json и т. Д.) Было совместимо с вашим новым объектом; не нужно вносить изменения в конфигурацию сериализатора.

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

Люди могут запутаться в том, что развязка должна происходить в обоих направлениях. Это не; это должно работать только в одном направлении. На практике вы никогда не сможете полностью отделиться; всегда есть некоторая связь. Цель слабой связи состоит в том, чтобы облегчить обслуживание кода, а не удалить все зависимости.

Роберт Харви
источник
Я согласен с вашим мнением о разделении. Сериализатор зависит от объекта домена, и это нормально. Но не наоборот. Однако я не согласен с вашим мнением об открытых средствах доступа к объектам домена. На практике они часто есть, да. Но IMO было бы предпочтительнее реализовать доменную логику в чистом объектно-ориентированном дизайне: скажи, не спрашивай . Но все же вам нужны средства доступа для сопоставления (ORM, сериализация, GUI ...). И это то, чего я хотел бы избежать, если это возможно.
EagleBeak
Как вы планируете получить доступ к своим полям, если у вас нет доступа?
Роберт Харви
На самом деле я имею в виду ни один из трех типов объектов, которые вы описываете, но «агрегаты» в терминологии DDD и их подобъекты (сущности, объекты значений). Теперь я понимаю, что мой вопрос не был достаточно ясен по этому поводу. Сожалею! Пожалуйста, смотрите мое редактирование выше.
EagleBeak
1
Это в основном нерешенная проблема - вы не можете использовать инкапсуляцию, развязку и сериализацию \ кодирование, одновременно подвергая DTO, - это один из способов достижения компромисса. Есть, однако, гораздо менее навязчивым способы: yegor256.com/2016/07/06/data-transfer-object.html
Basilevs
1
Это отбрасывает инкапсуляцию, любой может реализовать или использовать класс друга для чтения внутренних объектов объекта.
Базилевс
-1

Основная цель сериализации состоит в том, чтобы гарантировать, что данные, созданные одной системой, могут быть использованы одной или несколькими совместимыми системами.

Самый простой и надежный подход к сериализации - это перевод данных в независимый от типа формат, который поддерживает структуру в простом и удобном для использования формате. Например, наиболее распространенные форматы сериализации (например, JSON, XML) используют четко определенный текстовый формат. Текст прост в производстве, передаче и потреблении.

Есть две причины, по которым использование одного из этих форматов может быть не идеальным.

  1. КПД

    При переводе всех данных в текстовые эквиваленты заложена неотъемлемая плата. Типы данных не существовали бы, если бы текст был наиболее эффективным способом выражения всех различных форм данных. Кроме того, структура этих форматов не идеальна для получения подмножеств данных асинхронно или по частям.

    Например, XML и JSON предполагают, что используемые данные будут записаны и прочитаны от начала до конца. Для обработки очень больших наборов данных, когда памяти недостаточно, системе, потребляющей данные, может потребоваться возможность обрабатывать данные по частям. В этом случае для обработки данных может потребоваться реализация сериализации / десериализации специального назначения.

  2. точность

    Приведение, необходимое для сериализации / десериализации данных из их предполагаемого типа в независимый от данных тип, приводит к потере точности.

Можно утверждать, что создание двоичного представления объектов и данных, безусловно, является наиболее эффективным и точным решением. Основным недостатком является то, что реализация всех систем, которые как потребляют, так и производят данные, должны оставаться совместимыми. Это простое ограничение в теории, но на практике это кошмар, потому что производственные системы имеют тенденцию меняться / развиваться с течением времени.

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

Эван Плейс
источник
Извините, но это не отвечает на мой вопрос. Речь идет об отделении доменных объектов от сериализации, а не о причинах сериализации или преимуществах и недостатках различных форматов. Как я могу сериализовать доменные объекты без публичного раскрытия их частного состояния?
EagleBeak
@EagleBeak О, я не осознавал, что ты беспокоишься именно о том, как обращаться с частными членами. В вашем случае вы можете сериализовать в двоичном формате (при условии, что принимающая система следует тем же правилам / структуре, что и объекты домена), или написать некоторую логику, которая извлекает только общедоступные данные перед сериализацией.
Эван Плейс
Я думаю, что «обычное» предположение состоит в том, что данные, сериализуемые в формат общего назначения (например, xml, json), будут общедоступными, и эта привилегия будет контролироваться через API через ACL или какой-либо другой эквивалент. Сериализация / десериализация общего назначения больше подходит для отделения данных от бизнес-логики, переходящей из одной системы в другую.
Эван Плейс
Я согласен с тем, что общедоступные средства доступа обычно предполагаются для объектов, подлежащих сериализации. Но я все еще хотел бы узнать больше о том, как это связано с DDD и его сильным акцентом на инкапсуляцию логики домена. Все ли специалисты по DDD просто выставляют состояние модели домена через общедоступные средства доступа для сериализации (и никогда не упоминают об этом в своих примерах)? Я сомневаюсь в этом. Пожалуйста, не поймите меня неправильно. Я очень ценю ваш вклад. Просто меня интересует другой аспект. (Пока что я не думаю, что мой вопрос слишком расплывчат, но ответ Роберта Харви и ваш заставил меня задуматься об этом ..)
EagleBeak