Где проверить правила модели домена, которые зависят от содержимого базы данных?

10

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

Для каждого поля администратор может определить правило проверки, которое ограничивает допустимые значения для поля. Правила проверки могут быть любыми: от «значение, введенное в поле должно быть истинным или ложным» до «значение, введенное в поле, должно существовать в столбце A таблицы B в базе данных». Администратор может в любое время изменить Правило валидации для Поля.

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

Вариант № 1: проверка в доменной модели

Каждый объект поля будет содержать правило валидации, указанное администратором. Объекты Field также имеют ссылку на IValidator. Когда делается попытка установить значение поля, поле передает заданное значение и правило проверки в IValidator. Если данное значение недопустимо, исключение ValidationException будет выброшено и соответствующим образом обработано в графическом интерфейсе / интерфейсе другой системы.

Плюсы:

  • Надежная защита от случайного присвоения Полям значений, которые нарушают Правило валидации

Минусы:

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

  • В этом проекте модель поля имеет косвенную связь с уровнем доступа к хранилищу данных / репозиторием через IValidator. Внедрение сервисов / репозиториев в доменные модели, как правило, не одобряется .

Вариант № 2: проверка в сервисе

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

Конечно, Уровень доступа к данным не будет использовать Сервис при создании объектов Поля, которые ранее были сохранены в БД.

Плюсы:

  • Не нарушает мышление «не вводить сервисы / репозитории в ваши доменные модели».

  • Нет необходимости сохранять текущее правило проверки при сохранении поля. Служба может просто найти текущее правило проверки для поля; при просмотре данных истории значение поля не изменится.

Минусы:

  • Нет гарантии, что вся логика, которая должна использовать Сервис для установки значения поля, на самом деле делает это. Я вижу это как главный недостаток; все, что кажется, нужно, чтобы кто-то написал «thisField.setValue (thatField.getValue ())», и правило проверки thisField может быть нарушено, и никто не будет мудрее. Это может быть потенциально смягчено, если убедиться, что значение поля совпадает с правилом проверки, когда уровень доступа к данным собирается сохранить поле.

В настоящее время я предпочитаю вариант № 1, а не вариант № 2, главным образом потому, что я рассматриваю это как бизнес-логику и чувствую, что вариант № 2 представляет больший риск введения неверных данных в систему. Какой вариант вы предпочитаете, или есть другой дизайн, который подходит к этому сценарию лучше, чем два описанных варианта?

Редактировать (сложность проверок)

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

Сейчас я решил перейти к варианту № 1, стараясь не назначать слишком много обязанностей для модели предметной области. Те, кто сталкивается с подобной ситуацией, могут также захотеть проверить связанные вопросы Проверка и авторизация в многоуровневой архитектуре и Проверка ввода данных - Где? Как много? ,

Лаури Харпф
источник
Создание модели прекрасно работает со всеми проверками. Но когда вы хотите отредактировать или просмотреть форму, проверка включается тоже. Это вызывает исключение для полей, которые являются пустыми или имеют недопустимые значения - возможно, измененные в БД или загруженные из Excel. Ожидаемое решение - позволить форме отображаться при обновлении, чтобы администратор мог исправить эти поля.
Tunmise Fasipe

Ответы:

4

Насколько сложны проверки? Часто проверки требуют комбинации полей и / или бизнес-правил, которые полагаются на поля, чтобы быть точно оцененными.

Чем сложнее проверки, тем сложнее и менее производительный вариант № 2.

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

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

Учитывая приведенную выше информацию, вариант 1 представляется наиболее гибким, если вы соблюдаете дисциплину, разделяя проверку и постоянство.

deschaefer
источник
0

Может быть, вам не хватает слоя. Не зная деталей вашего приложения (реквизиты, архитектура и т. Д.), Я бы сделал что-то вроде Клиента (кем бы он ни был) -> Служба приложений -> Модель домена

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

FieldUpdateService >> updateField(fieldId, newValue)
  List<FieldRule> rules = this.rulesRepository.findRulesFor(fieldId)
  Field field = this.fieldRepository.find(fieldId)
  try 
    field.updateValue(rules,newValue)
    fieldRepository.save(field)
  catch 
    // manage error

Если у вас есть связь между Полем и его FieldRules и вы используете ORM, такой как Hibernate в Java, вы будете делать только:

FieldUpdateService >> updateField(fieldId, newValue)
  Field field = this.fieldRepository.find(fieldId)
  try 
    field.updateValue(newValue)
    fieldRepository.save(field)
  catch 
    // manage error

Field >> updateValue(newValue)
  for rule in rules
     if !rule.isValid(newValue)
        throw ValueNotAllowedException
  this.value = newvalue

Потому что запрос ORM и создает граф объектов, которые вы запрашиваете.

Что касается ваших сомнений в том, что кто-то может сделать

thisField.setValue (thatField.getValue ()) "и Правило валидации thisField может быть нарушено, и никто не будет мудрее

Кто-то также может написать: FieldRule alwaysReturnTrueRule = new FieldRule {isValid (newValue) {return true; }} field.updateValue ("uncheckedValue", alwaysReturnTrueRule) Это неясный пример, но я хочу сказать, что ничто не защищает вас от неправильного использования кода. Возможно хорошая документация и общение лицом к лицу. Я думаю, что ничто не защищает вас от неправильного использования кода.

gabrielgiussi
источник