Правильно ли смоделирован этот пример в подходе DDD? - PullRequest
10 голосов
/ 03 апреля 2010

Просто создал акк на SO, чтобы спросить это:)

Предполагается, что этот упрощенный пример: создание веб-приложения для управления проектами ...
Приложение имеет следующие требования / правила.

1) Пользователи должны иметь возможность создавать проекты, вставляя имя проекта.
2) Имена проектов не могут быть пустыми.
3) Два проекта не могут иметь одинаковое имя.

Я использую 4-уровневую архитектуру (пользовательский интерфейс, приложение, домен, инфраструктура).
На моем уровне приложений у меня есть следующий класс ProjectService.cs:

public class ProjectService
{
    private IProjectRepository ProjectRepo { get; set; }

    public ProjectService(IProjectRepository projectRepo)
    {
        ProjectRepo = projectRepo;
    }

    public void CreateNewProject(string name)
    {
        IList<Project> projects = ProjectRepo.GetProjectsByName(name);
        if (projects.Count > 0) throw new Exception("Project name already exists.");

        Project project = new Project(name);
        ProjectRepo.InsertProject(project);
    }
}

На моем уровне домена у меня есть класс Project.cs и интерфейс IProjectRepository.cs:

public class Project
{
    public int ProjectID { get; private set; }
    public string Name { get; private set; }

    public Project(string name)
    {
        ValidateName(name);
        Name = name;
    }

    private void ValidateName(string name)
    {
        if (name == null || name.Equals(string.Empty))
        {
            throw new Exception("Project name cannot be empty or null.");
        }
    }
}




public interface IProjectRepository
{
    void InsertProject(Project project);
    IList<Project> GetProjectsByName(string projectName);
}

На моем уровне инфраструктуры у меня есть реализация IProjectRepository, которая выполняет фактические запросы (код не имеет значения).


Мне не нравятся две вещи в этом дизайне:

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

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

Итак, мой вопрос, с точки зрения DDD, это правильно смоделировано или вы сделали бы это по-другому?

Ответы [ 2 ]

2 голосов
/ 10 апреля 2010

Процесс создания нового проекта включает в себя две проверки (не нулевые и не дублирующие). В моем проекте выше эти две проверки разбросаны в двух разных местах, что затрудняет (imho) видеть, что происходит.

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

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

1 голос
/ 03 апреля 2010

Я думаю, что часть путаницы с (1) заключается в том, что вам не хватает слоя - вставьте сервисный слой в свою архитектуру, и ваша проблема исчезнет, ​​как волшебство. Вы можете поместить сервис и реализацию репозитория на уровень сервиса, то есть у вас есть сервис, который использует конкретную реализацию репозитория. Другие службы могут свободно выбирать альтернативную реализацию хранилища, если они этого хотят. Ваше приложение может свободно выбирать любой интерфейс сервиса, который ему нравится. Сказав это, я не уверен, что это действительно имеет значение в большинстве случаев. Почти во всех моих приложениях у меня есть один «домен / слой данных», который в основном исправлен. Я мог бы наложить репозиторий на него или нет в зависимости от того, насколько сложна бизнес-логика. То же самое с сервисом - это может просто не понадобиться, если проект не очень сложный. Если это станет так позже, я всегда могу рефакторинг. Обычно я помещаю свой репозиторий в тот же проект, что и мой контекст данных (с использованием LINQ), и, если есть служба, она будет в отдельном проекте (потому что, как правило, он также будет отображаться как веб-служба).

Что касается (2), вам нужно подумать о проблеме с точки зрения параллелизма. Ваша проверка на наличие дублированного имени лучше всего обрабатывается ограничением базы данных, если это возможно. Я думаю, что это самый простой способ применить эту логику. Вы, конечно, можете проверить, есть ли дубликат перед попыткой вставки, но если вы не сделаете это внутри транзакции, вы не сможете гарантировать, что другой процесс не появится и вставит один между вашим чеком и вставкой. Ограничение базы данных решает эту проблему. Перемещение чека в логику вставки (та же транзакция) также решает проблему, но, несмотря на это, я думаю, вам нужно быть готовым к обработке ее как ошибки вставки, а также (или вместо) ошибки проверки.

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