Доступ к данным для проверки и определения значений по умолчанию с использованием DDD - PullRequest
3 голосов
/ 28 марта 2011

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

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

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

Опции, которые мне известны:

  1. Переместить валидацию за пределы самой сущности. Возможно, валидация переносится в набор сервисов или отдельную услугу для каждой сущности, которая анализирует текущее состояние всей сущности и считает ее действительной или нет, а также предоставляет события домена или другие объекты значения, которые дают более полное представление о том, какие правила валидации имеют был сломан. В этом случае я все еще немного обеспокоен тем, как служба получит доступ к необходимой информации об инструкторах
  2. Разрешить доступ к репозиторию инструкторов от необходимых объектов, которые пытаются выполнить эту проверку.
  3. Создать сервис, который позволяет получить доступ к списку инструкторов по категориям инструментов. В качестве альтернативы создайте две отдельные службы: одну, которая возвращает информацию о том, находится ли данный инструктор в списке инструкторов для данной категории, и другую, которая возвращает инструктора по умолчанию для данной категории.
  4. Загрузите список объектов значений инструктора в моем сводном корне (вероятный студент или запрос на зачисление студента), который может использоваться для проверки либо совокупным корнем, либо сущностями, содержащимися в корне.

В любом из первых двух случаев, описанных выше, кажется, что использование репозитория инструкторов было бы излишним, потому что мне не нужен доступ к корню агрегата, представляющему инструктора, но вместо этого в моем случае я бы увидел инструктора какобъект-значение, описывающий запрос на зачисление учащегося и имеющий объекты-ценности для репозитория, кажется, размывает линии того, что должен делать репозиторий.Для последних двух вариантов кажется неправильным, что два варианта разрешают доступ к данным из службы или фабрики в случае варианта 4, так как не должны ли репозитории отвечать за доступ к данным, как этот?И если репозитории являются подходящим местом для этой логики, где находятся подходящие места для доступа или хранения ссылок на репозитории?Я был убежден, что есть причины не получать прямой доступ к репозиториям внутри какой-либо сущности или объекта-значения, составляющего модель, поэтому я задаюсь вопросом, может ли это быть причиной, когда мне придется отклониться от этого предположения.Я должен также упомянуть, что я довольно новичок в DDD, и я только сейчас сталкиваюсь с некоторыми моментами, когда я ломаю голову, и стараюсь не ограничивать себя, так что любой знающий вклад в эту тему будет полезен.

Ответы [ 2 ]

3 голосов
/ 28 марта 2011

Переместить валидацию за пределы самой сущности.

Один инструктор не должен знать обо всех других инструкторах.Проверка в отношении набора инструкторов не является обязанностью одного конкретного инструктора.

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

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

Создайте сервис, позволяющий получить доступ к списку инструкторов по категориям инструментов.

Этот бит информации показывает отсутствиесовокупный корень - я бы назвал это InstrumentClass.

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

Следующее, что вам нужно выяснить, - это как правильно описать ученика, назначенного в класс.К сожалению, я не могу назвать это в настоящее время (возможно Participation?).Но эта сущность будет использоваться для InstrumentClass, чтобы выяснить, какие инструкторы слишком заняты.


Вот мой «свободный стиль» (просто чтобы показать, что я вижу) при моделировании вашего домена:

using System;

public class Main{
  public Main(){
    var instructor = new Instructor();
    var instrument = new Instrument("saxaphone");
    var saxaphoneClass = new InstrumentClass(saxaphone,teacher);
    var me=new Person("Arnis");
    //here, from UI, I can see available classes, choose one
    //and choose according instructor who's assigned to it
    var request=me.RequestEnrollment(saxaphoneClass, instructor);
    saxaphoneClass.EnrollStudent(request);
  }
}
public class Person{
  public IList<EnrollmentRequest> EnrollmentRequests { get; private set; }
  public EnrollmentRequest RequestEnrollment
   (InstrumentClass instrumentClass,Instructor instructor){
    if (!instrumentClass.IsTeachedByInstructor(instructor))
      throw new Exception("Instructor does not teach this music instrument");
    var request=new EnrollmentRequest(this,instrumentClass,instructor);
    EnrollmentRequests.Add(request);
    return request;
  }
}
public class EnrollmentRequest{
  public Person Person{ get; private set; }
  public InstrumentClass InstrumentClass { get; private set; }
  public Instructor Instructor{ get; private set; }
}
public class InstrumentClass{
  public void EnrollStudent(EnrollmentRequest request){
    var instructor=request.Instructor;
    var student=new Student(request.Person);
    var studies=new Studies(this,student,instructor);
    //TODO: this directiveness isn't good
    //student/instructor should listen for class events themselves
    //and class should listen if by any reason instructor or student cannot
    //participate in studies
    student.EnrollInClass(studies);
    instructor.AssignStudent(studies);
    Studies.Add(studies);
  }
  public bool IsTeachedByInstructor(Instructor instructor){
    return Instructors.Contains(instructor);
  }
  public InstrumentClass
   (Instrument instrument, params Instructor[] instructors){
    Instrument=instrument; Instructors=instructors.ToList();
  }
  public IList<Instructor> Instructors{get;private set;}
  public IList<Studies> Studies { get; private set; }
  public Instrument Instrument { get; private set; }
}
public class Studies{
  public Student Student { get; private set; }
  public Instructor Instructor { get; private set; }
  public InstrumentClass InstrumentClass { get; private set; }
}
public class Student{
}
public class Instructor{
}
public class Instrument{
}
1 голос
/ 03 апреля 2011

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

Помните, что в большинстве случаев вы не сможете получитьмодель правильно с первого раза и нужно развивать модель.По мере того, как вы «играете с этим», некоторые жесткие части станут более гибкими для изменения.(Как садовая перчатка по аналогии с Эриком).По мере того, как вы получаете новое понимание предметной области, вы обнаружите, что вам необходимо внедрить новые концепции в вашу модель.Использование «простых примеров» сопряжено с опасностями, например, им может не хватать глубины.Но иногда нужны простые примеры, чтобы освоить DDD, и, к счастью, мы можем развить пример ;)

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

Установив контекст, у меня, таким образом, будет предложение , как изложено ниже:

Enterprise Patterns и MDA имеет несколько сложных шаблонов, но идея, которую вы можете убрать, - это CapacityManager архетипа Inventory в качестве руководства.К сожалению, модель на стр. 278 недоступна в Интернете, но посмотрите на архетип ServiceInventory.

Преподаватели продают свои услуги студентам.(Инструкторы получают зарплату в прошлый раз, когда я проверял :).Если бы я сопоставил ваш пример с архетипом Inventory для идей, я бы использовал:

  • Inventory - список инструментов / курсов
  • ServiceType - сведения об инструментах / курсах, начало и конец и т. Д.
  • ServiceInventoryEntry - Инструмент + доступные места (использует диспетчер емкости)
  • ServiceInstance - Enrollment - место в классе (Запланировано, Забронировано, Отменено, Завершено)
  • CapacityManager (используется ServiceInventoryEntry)
  • ReservationRequest - Запрос на регистрацию

Я думаю, что ключевой концепцией является CapacityManager: Вы можете вызвать метод ServiceInventoryEntry :: getCourses (), который будет использовать методCapacaityManager (служба или класс), чтобы показать вам / рассчитать доступных учителей или вернуть по умолчанию.Таким образом, вызывайте его несколько раз в зависимости от контекста: по умолчанию или предложите список доступных мест / мест / инструкторов.

С помощью этой модели вы сможете найти естественное место (где и когда) для проверки.Руководство по Упорядоченному объектному моделированию состоит в том, чтобы поставить проверку там, где находятся данные.Не следует воспринимать это как жесткое правило, но у объектов есть естественная тенденция объединять правильные задачи и данные.Например, менеджер по мощности знает о регистрации и инструментах.(Из MDA - CapacityManger: управляет использованием емкости, выпуская ServiceInstances)

Чтобы ваши агрегаты видели, какие транзакции / изменения вы будете делать, чтобы вы могли убедиться, что они применяют инварианты (правила).В вашем примере я бы сделал ServiceType (Course) объектом-значением, а ServiceInventoryEntry и ReservationRequests агрегировали корни.(Зависит от того, насколько сложным вы хотите придерживаться своих правил).Вы также можете добавлять учеников и учителей в партии, как указано в книге MDA.Я склонен использовать репозитории, чтобы получить свои агрегаты, а затем также полагаюсь на инверсию управления, согласно книге Джимми, на которую вы ссылались.

Причина, по которой мне нравятся паттерны MDA, заключается в том, что они заставляют меня думать об использованиислучаи и модельные концепции, которые я или бизнес не могли бы себе представить .Но будьте осторожны, только моделируйте то, что вам нужно , так как шаблоны MDA могут быть большими и даже соблазнительными.Хорошо, что они спроектированы так, чтобы быть модульными или «масштабируемыми».

Короче говоря: - Ваши совокупные корни должны гарантировать, что ваш домен находится в допустимом состоянии (Правила / Инварианты).Лидирование, где данные. Ваша модель будет направлять вас.

...