Разделение данных на слои

Согласно Мартину Фаулеру при разработке архитектуры полезно разделять на 3 слоя: Презентационный, Доменный и Доступа к данным.

Польза от выделения слоев состоит в:

  • Уменьшение области внимания при разработке каждого из уровней и рассмотрение их независимо друг от друга

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

  • Границы слоев облегчают тестирование взаимодействий между слоями.

DDD подход vs деление на слои

Domain Driven Design - говорит нам о необходимости договориться о едином языке для предметной области и использовать его всеми членами команды.

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

Следствием этого является однозначное понимание атрибутов объектов используемых в моделях данных.

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

Вопросы и проблемы при использовании слоеной архитектуры и принципа DDD.

Рассматриваемый пример это письмо от Клиента Юридического лица в Банк.

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

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

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

Создание. Презентационный слой

Модель данных на презентационном слое представляют из себя набор значений необходимых для построения экранных форм. Базовые действия который выполняет пользователь это:

  • Поиск

  • Создание

  • Изменение

Предположим, что Клиент создает Жалобу или Предложение. Модель данных для формы ввода будет выглядеть:

ClientLetter:
      description: Письмо
      type: object
      properties:
        subject:
          description: Тема письма
          type: string
        content:
          type: string
          description: Содержимое письма
        type:
          description: тип письма
          type: string
          enum:
          - claim
          - proposal

Этих данных достаточно для заполнения формы, но не достаточно для создания документа в БД. Не хватает информации о клиенте.

Создание. Доменный слой

Для сохранения письма в БД необходима информация о Клиенте. Клиент был аутентифицирован в приложении, таким образом существует сессионный контекст из которого могут быть взяты данные Клиента для сохранения письма. Именно данные клиента из Сервиса Аутентификации должны быть использованы для операций сохранения в БД, нельзя доверять данным о клиенте переданным из браузера. Так же необходимо ограничить необходимым объем данных передаваемых на PL слой.

ClientLetter:
    description: Letter
    type: object
      properties:
        client:
            type: object
            properties:
                id:
                    type: integer
                    description: client identifier
                name:
                    type: string
                    description: person name who created the letter
        subject:
          description: Subject
          type: string
        content:
          type: string
          description: Body
        type:
          description: type of letter
          type: string
          enum:
          - claim
          - proposal

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

Данный подход гарантирует нам что данные клиента не будут подменены.

Создание.Слой данных

Модель данных на этом слое может быть представлена в таком виде:

ClientLetter:
    description: Letter
    type: object
      properties:
        client:
            type: object
            properties:
                id:
                    type: integer
                    description: client identifier
                name:
                    type: string
                    description: person name who created the letter
        subject:
          description: Subject
          type: string
        content:
          type: string
          description: Body
        type:
          description: type of letter
          type: string
          enum:
          - claim
          - proposal
        changed:
            description: date and time of transaction
            type: datetime
        system:
            description: system that pass data to the DB
            type: string

Как можно заметить на Дата слое были добавлены: системное дата и время и система, которая выполнила создание записи в БД.

Создание писем может быть реализовано по разным каналам WEB приложением, Мобильным приложением и даже сотрудником Банка от имени Клиента. Все это требует расширения модели хранения.

Создание. Выводы

Рассмотрев модель данных на разных слоях на примере письма мы убедились в том что необходимо иметь разные модели данных на разных уровнях по мере движения данных от Презентационного слоя к Слою Хранения данных. Необходимость диктуется как функционалом реализуемом на каждом слое, так и соображениями безопасности чувствительных данных.

Извлечение. Презентационный слой

Давайте рассмотрим каким образом пользователи ищут объекты, в нашем примере Письма. Пользователь задает условия поиска и фильтрации.

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

Это значит что при извлечении данных в общем случае нужно два поисковых метода:

  • Списковый метод, который содержит в параметрах запроса условия поиска и фильтрации

  • Детальный метод, который в параметрах запроса передает конкретных идентификатор объекта.

Извлечение. Слой Данных

Мы обсуждаем списковый метод, который задает условия поиска и фильтрации. Поля таблицы, по которым производится поиск по API метода фиксируется в контракте. Таким образом мы имеем ограниченый набор полей для поиска. Для работы метода, возвращающего список поля поиска необходимо индексировать.

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

id

version

client_id

status

type

last_changed

data

1

1

123

1

1

01/01/2022

{data}

Атрибуты, хранимые в отдельных столбцах индексированы и используются для поиск и фильтрации. Все остальные поля можно хранить в формате JSON в одном столбце таблицы.

Извлечение. Презентационный слой. Проблема идентификаторов

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

Для реализации сценария очевидный путь это передать на Презентационный слой идентификаторы объектов в методе списка и реализуя выбор пользователя передать из PL слоя выбранный идентификатор письма в Детальный метод, который вернет полный набор атрибутов Письма.

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

Каким образом можно решить проблему выбора одного объектов из набора переданного на Презентационный слой?

Одним из подходов может быть использование синтетических идентификаторов на Презентационном слое. Бизнес слой должен сформировать либо хеш идентификаторы либо пронумеровать объекты переданные на Презентационный слой. Пользователь выбрав синтетический идентификатор передают его в Детальный метод на Бизнес слой. Бизнес слой вычисляет реальный идентификатор объекта и передает его в Слой Данных при обработке Детального метода.

Извлечение. Выводы

При реализации поиска и выбора данных имеет смысл использовать CQRS с помощью которого данные можно получить удобным способом.

Плохой практикой является использование идентификаторов объектов на Презентационном слое. С целью соблюдения требований безопасности лучше использовать синтетические идентификаторы объектов не раскрывая формата и типа идентификаторов из слоя Данных.

Комментарии (0)