Подтвердить что ты не робот

Имея модель отдельного домена и модель сохранения в DDD

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

  • Имейте 1 класс, который служит как модель домена, так и модель сохранения.

  • У вас есть 2 разных класса, один из которых реализует логику домена, а другой - для подхода, основанного на кодах

Теперь я знаю мнение 1), как говорят, упрощает небольшие решения, которые не имеют много различий между моделями домена и персистентности, но я думаю, что это нарушает принцип единой ответственности и тем самым вводит множество проблем, когда соглашения ORM мешают DDD.

Что для меня неожиданно, есть многочисленные примеры кода, как реализовать мнение 1). Но a не нашел ни одного примера того, как реализовать мнение 2) и как сопоставить 2 объекта. (Наверное, есть такие примеры, но я не смог найти С# один)

Итак, я попытался реализовать пример самостоятельно, но я не уверен, что это хороший способ сделать это.

Скажем, у меня есть система билетов и билеты имеют срок действия. Моя модель домена будет выглядеть так:

/// <summary>
/// Domain Model
/// </summary>
public class TicketEntity
{
    public int Id { get; private set; }

    public decimal Cost { get; private set; }

    public DateTime ExpiryDate { get; private set; }

    public TicketEntity(int id, decimal cost, DateTime expiryDate)
    {
        this.Id = id;
        this.Cost = cost;
        this.ExpiryDate = expiryDate;
    }

    public bool IsTicketExpired()
    {
        if (DateTime.Now > this.ExpiryDate)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

Модель персистентности с использованием Entity Framework как ORM будет выглядеть почти так же, но по мере роста решения это может быть не так.

/// <summary>
/// ORM code first Persistence Model
/// </summary>
public class Ticket
{
    [Key]
    public int Id { get; set; }

    public decimal Cost { get; set; }

    public DateTime ExpiryDate { get; set; }
}

Все выглядит великолепно. Теперь я не уверен, что это лучшее место для получения модели сохранения Ticket из репозитория и как сопоставить ее с моделью TicketEntity

Я сделал это на уровне приложения/службы.

public class ApplicationService
{
    private ITicketsRepository ticketsRepository;

    public ApplicationService(ITicketsRepository ticketsRepository)
    {
        this.ticketsRepository = ticketsRepository;
    }

    public bool IsTicketExpired(int ticketId)
    {
        Ticket persistanceModel = this.ticketsRepository.GetById(ticketId);
        TicketEntity domainModel = new TicketEntity(
            persistanceModel.Id,
            persistanceModel.Cost,
            persistanceModel.ExpiryDate);

        return domainModel.IsTicketExpired();
    }
}

Мои вопросы:

  • Есть ли какие-либо соображения по соображениям 1) предпочли бы мнение 2), кроме ускорения разработки и повторного использования кода.

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

4b9b3361

Ответ 1

Есть ли какие-либо соображения по соображениям 1) предпочли бы мнение 2), кроме ускорения разработки и повторного использования кода.

Вариант 1 - это просто из-за чистой лени и воображаемой увеличенной скорости развития. Верно, что эти приложения быстрее получат версию 1.0. Но когда эти разработчики достигают версии 3.0 приложения, они не считают, что это так весело поддерживать приложение из-за всех компромиссов, которые они должны были делать в модели домена из-за устройства ORM.

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

Да. Репозиторий должен нести ответственность за скрытие механизма сохранения. Он API должен работать только с объектами домена, а не с сущностями.

Репозиторий отвечает за выполнение преобразований в/из объектов домена (чтобы их можно было сохранить). Метод извлечения обычно использует ADO.NET или ORM, например Entity Framework, для загрузки объекта/объекта базы данных. Затем преобразуйте его в правильный бизнес-объект и, наконец, верните его.

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

Если вы работаете с сервисами приложений в определении DDD, вам, вероятно, захочется взглянуть на шаблон разделения команд/запросов, который может быть заменой приложений. Код становится чище, и вы также получаете гораздо более легкий API-интерфейс для вашей модели домена.

Ответ 2

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

1) Персистенция и модель домена как одно и то же

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

С помощью Entity Framework в качестве ORM вы можете почти поддерживать ваши модели домена полностью свободными от проблем с ORM, используя плавные сопоставления.

Хорошие детали:

  • Быстро, легко, красиво (если база данных предназначена для этой проблемы)

Плохие части:

  • Возможно, разработчики начинают думать дважды, прежде чем делать изменения/рефакторинг в домене, опасаясь, что это повлияет на базу данных. Этот страх не подходит для домена.
  • Если домен начинает слишком сильно отклоняться от базы данных, вам придется столкнуться с некоторыми трудностями для поддержания домена в гармонии с ORM. Чем ближе к домену, тем сложнее настроить ORM. Чем ближе к ORM, тем грязнее домен получает.

2) Модель Persistence and Domain как две разделенные вещи

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

Хорошие детали:

Плохие части:

  • Дополнительные усилия с преобразованием данных между слоями. Время разработки (возможно, также время выполнения) будет медленнее.

  • Но главный и, поверьте, что будет больнее: вы потеряете основные преимущества использования ORM! Как отслеживание изменений. Возможно, вы в конечном итоге будете использовать фреймворки, такие как GraphDiff или даже отказаться от ORM и перейти к чистым ADO.NET.

Есть ли какие-либо проблемы в моем подходе к отображению моделей?

Я согласен с @jgauffin: "он в репозитории должен иметь место". Таким образом, ваши модели Persistence никогда не выйдут из уровня репозитория, в предпочтении никто не должен видеть эти объекты (кроме самого репозитория).

Ответ 3

Есть ли какие-либо причины 1) предпочли бы мнение 2) кроме ускорения разработки и повторного использования кода.

Я вижу большой (упрямый материал впереди): нет "модели сохранения". Все, что у вас есть, это реляционная модель в вашей базе данных и объектная модель домена. Сопоставление между двумя представляет собой набор действий, а не структур данных. Что еще, это именно то, что должны делать ORM.

Большинство ORM теперь поддерживают то, что они должны были предоставить с самого начала, - способ объявить эти действия непосредственно в коде, не касаясь объектов домена. Разумные конфигурации Entity Framework позволяют вам это сделать.

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