Дизайн, управляемый доменом - Модель домена против Hibernate Entity - PullRequest
0 голосов
/ 19 апреля 2019

Являются ли Hibernate Entity такими же, как модели домена?

См. Следующий пример.

Метод 1 - Модель домена и Entity одного класса. Модель предметной области "is-an" объект

@Entity
@Table(name = "agent")
class Agent
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(name = "agent_number", unique = true, nullable = false)
    private String agentNumber;

    @Column(name = "agent_name", nullable = false)
    private String agentName;

    // Busines logic methods
}

Метод 2 - Домен и объект - разные функции. Модель предметной области «имеет-сущность»

class Agent
{
    // Hibernate entity for this domain model
    private AgentEntity agentEntity;

    // Getters and setters to set the agentEntity attributes

    // Business logic
}

Из приведенных выше двух методов, какой из них является правильным способом реализации DDD?Я полагаю, что метод 2 - правильный путь, потому что вы по существу управляете доступом к чувствительному объекту, а включающий объект (модель домена) имеет всю бизнес-логику / операции в модели домена.Но мои коллеги на рабочем месте предполагают, что они по сути одинаковы.И в соответствии с ними целью Hibernate Entity является представление модели предметной области в данной системе.Моделирование сущности как модели предметной области фактически упрощает проектирование.Это связано с тем, что хранилище использует Entity для выполнения операций CRUD.Таким образом, если модель имеет сущность «имеет», то хранилище должно быть зависимостью, введенной в модель предметной области, чтобы сохранить сущность.Это сделает конструкцию излишне сложной.

Ответы [ 2 ]

1 голос
/ 19 апреля 2019

Поскольку вы упомянули технологию в данном случае Hibernate, это означает, что вы говорите о реализации . Дизайн, управляемый доменом, касается как абстрактного, например, Модель и Реализация .

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

Эта статья рассказывает о проблеме, с которой вы столкнулись.

Вы спросили, совпадает ли модель домена с Hibernate Entity . Ответ NO .

Hibernate Entity - это специфическая для технологии вещь, в данном случае это объект, который является частью инфраструктуры ORM. Hibernate Entity и DDD Entity в соответствии с определением DDD - это разные вещи, так как DDD Entity является абстрактной вещью, если определяет идею (шаблон) и дает рекомендации что это за идея и что она представляет. Hibernate Entity - это объект Java, который создается, отслеживается, сохраняется, отбрасывается и мусор собрал.

Люди просто используют один и тот же термин для разных вещей, и это может привести к путанице (не могу их винить, называть вещи - одна из двух трудных проблем в программном обеспечении).

Вы используете Hibernaty Entities или любой другой тип специфичной для технологии вещи, такой как Entity Framework Entity (это то же самое, объект в OO-программе) для реализации Модель домена . Одна и та же модель домена может быть реализована на разных языках с использованием разных технологий. Эти реализации будут варьироваться в зависимости от того, что обеспечивает технология.

Например, если вы пишете серверную часть NodeJ с MongoDB и хотите использовать ORM для реализации доменной модели , вы застрянете с использованием шаблона активной записи ( вероятно, Mongoose), потому что это единственные, которые реализовали люди (по крайней мере, я не смог найти другие фреймворки, которые не являются Active Record, если вы найдете какие-либо, пожалуйста, дайте мне знать). Реализация DDD таким способом может быть очень сложной (и может действительно отстойной).

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

Иногда у ORM есть требования, и вы не хотите показывать эти вещи вашему другому коду, поэтому вы можете использовать Wrapper, как в Method 2 . Некоторые из них включают в себя такие вещи, как публичный метод get set, публичные конструкторы и т. Д. Большинство из них используют отражение и могут иметь личные вещи, но все же есть много проблем, таких как наличие частного конструктора без параметров для удовлетворения фреймворка, и ваш код сильно запутывается вещей, которые не имеют отношения к вашей модели, но есть, потому что они нужны вашей инфраструктуре (YUCK!). Это может привести к ошибкам тоже. Проще ошибиться, имея конструктор по умолчанию, а не красивые конструкторы с параметрами или статическими фабричными методами. Эта оболочка может представлять более чистую модель предметной области без наличия необходимого зла , которое несут фреймворки, чтобы вы могли их использовать.

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

0 голосов
/ 19 апреля 2019

Является ли Hibernate Entity такой же, как модели домена?

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

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

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

Другими словами, хранилище - это (в некотором смысле) две функции;один знает, как извлечь данные из «агрегата» и хранилища, другой знает, как считывать данные из хранилища и создавать из него агрегат.

ORM - это один из способов получения данных извнешняя реляционная база данных в локальную память.

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

Use an identifier to load data from the database into a hibernate entity
copy the data from the hibernate entity into an aggregate
return the aggregate

А хранилище может выглядеть как

Copy data from the aggregate into a hibernate entity
Save the hibernate entity.

На практике это своего родаболь.Представлению ORM часто приходится беспокоиться о таких вещах, как суррогатные ключи, отслеживание грязных элементов данных, чтобы оно могло оптимизировать записи, и т. Д.

Вместо этого вы часто будете видеть, что логика домена заканчиваетсязаписывается в сущности ORM, и вы добавляете кучу комментариев, чтобы прояснить, какие биты присутствуют, потому что они требуются hibernate.

Если вы посмотрите на DDD Cargo shipping Например, вы увидите, что они выбрали этот второй подход, в котором агрегат имеет небольшую поддержку гибернации , скрытую внизу.

Домен и сущность - это разные функции.Модель предметной области «имеет-сущность»

Ваши коллеги правы: они эквивалентны в большинстве важных аспектов.Модель предметной области зависит от ваших спящих сущностей.

Ни один из них не соответствует тому, что Эванс описал в своей книге.

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

Если бы вы на самом деле разделяли их, то ваш репозиторий выглядел бы примерно так:

Agent AgentRepository::find(id) {
    AgentEntity e = entityManager.find(id)
    Agent a = domainFactory.create( /* args extracted from e */ )
    return a
}

void AgentRepository::store(Agent a)
    AgentEntity e = entityManager.find(id)
    copy(a, e)
}

// I think this is equivalent
void AgentRepository::store(Agent a)
    AgentEntity e = entityManager.find(id)
    entityManager.detach(e)
    copy(a, e)
    entityManager.merge(e)
}

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

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

...