Страницы

Поиск по вопросам

вторник, 29 января 2019 г.

Как спроектировать проект? DTO, Anemic, MVVM

Что имеем:
Проект представляет из себя WPF приложение, взаимодействующее с сайтом, локальной БД и отображающее данные в пользовательском интерфейсе.
Пример работы:
На сайте есть что-то вроде топиков, которые время от времени обновляются. Нужно "скачивать" последнее состояние этих топиков и писать в локальную базу, назовем это синхронизацией. После синхронизации мы можем осуществлять быстрый поиск по базе, делать различные пометки, добавлять в избранное и т.д., взаимодействуя через интерфейс пользователя.
Видение структуры:
Модель получается одна, что для базы, что для MVVM. Однако еще я хочу создать также слой API, который будет взаимодействовать с сайтом и возвращать экземпляры моделей. Но тогда и в API понадобится модель.
В итоге получается 2 слоя (или 3?) - API и БД (+ MVVM). Работают с одной моделью. Значит нужно использовать Anemic модель? Или лучше разделить модели, для каждого слоя сделать свою?
Теперь про логику взаимодействия с VM. Если пользователь захочет получить топики по критериям, VM должен запустить синхронизатор, дождаться завершения и только после этого делать запросы к базе. Правильно ли будет синхронизаторы (парсеры), которые через API будут получать топики и обновлять их в базе, выделить в отдельные классы или предоставить эту логику VM-мам?

Что получилось:
Слой API, взаимодействующий с сайтом Слой БД Синхронизаторы, связывающие API и БД VM-ы, взаимодействующие с БД и API через синхронизаторы Общая DTO Anemic модель для API, БД и MVVM.

Правильно ли использовать данные разделения и подход к проектированию в целом?


Ответ

Жуткий поток сознания, который сложно понять.
У вас по сути десктопное приложение клиент к какому то сайту, которое позволяет забирать данные с сайта, просматривать их оффлайн и добавлять какую-то мета-информацию. А значит вот вам мои фломастеры...
Я предпочитаю подход, где есть модели(сущности) и сервисы, которые что-то могут сделать с этими сущностями, то есть anemic.
Модели (сущности) Не стоит плодить dto без надобности. А значит модель(сущность) "топик" будет одной для бд и для клиента сайта и для вьюмоделей, пока не потребуется иначе.
Слой доступа к данным - от него зависит всё. Я предпочитаю рассматривать его как внешнее хранилище. А это значит, что есть подобие Repository/Storage, из которого можно достать данные или положить. Он должен принимать сущности на своем внешнем уровне и внутри себя хранить как ему вздумается. Например быть разделенным на 2 слоя - верхний слой работает с сущностями, а нижний с простыми типами.
Тут много вариантов реализаций и от него зависит будут ли модели anemic. Я не приветствую rich model, которая знает как себя хранить, но модель, вырожденная в dto - тоже плохо, поэтому у меня модели содержат и данные и некоторые методы, которые мешают сохраняться напрямую и инода вынуждают использовать dto (но на практике у меня от dto больше проблем, чем от чистого anemic)
Клиент к сайту - модуль-обертка. В простом случае это 1-2 класса, которые прячут внутри себя сетевые запросы и трансляцию данных их в сущности. Вводить собственные типы данных на границе модуля (и возможно писать дополнительный адаптер/маппинг) есть смысл только если этот модуль будет переиспользоваться в других проектах или очень хочется большей изоляции модулей или у нас ORM, который сильно мешает. Иначе нарушаем YAGNI
Вид (WPF+MVVM) - WPF отображает, а MVVM предоставляет данные для отображения и связывает вид с моделью. MVVM дает данные для отображения и бегает в модель за данными или с просьбой выполнить какую то работу, но сам не содержит логику приложения. Его дело связать вид и логику приложения. Хотя даже при этом вьюмодели получаются жирными, поэтому некоторые добавляют контроллеры (MVVMC) к вьюмоделям, которые и берут на себя общение с моделью.
Синхронизация - это сервис, который относится к модели (не путать с сущностями), а не к виду, поэтому существует не как часть вьюмоделей.
Так мы получили условно модули. Работает все это вместе так:
Пользователь нажимает кнопку "синхронизировать" WPF кнопка забиндена на команду вьюмодели и срабатывает эта команда вьюмодель прямо или косвенно обращается к сервису синхронизации и просит "синхронизируй". Сама вьюмодель ничего большего не делает Сервис синхронизации используя клиент к сайту получает данные в виде сущностей и передает их слою базы данных для хранения. вьюмодель или ждет окончания синхронизации или использует события. вьюмодель отображает данные (лезет за ними в бд например) Те же сущности используются для отображения, ну разве что оборачиваются вьюмоделями(хорошая привычка).
Остались еще дополнительные данные, которых нет на сайте - пометки, метка "избранное" и так далее. Их можно хранить отдельно от сущности "топик", а можно как часть этой сущности (клиент к сайту просто не затронет те поля, что не знает). Декомпозиция слишком спорный процесс - я вот не люблю много колонок в бд, но сохранение и вычитывание графа тоже писать лениво.
Введение DTO - только при необходимости. DTO или сущности конкретного модуля (или использование простых типов) позволяют добиться большей изоляции модуля...но YAGNI требует подумать "а оно нам надо?"
Старайтесь обозначить границы модулей, чтобы работать только с ними. При этом внутренности модуля скрыты. Даже если нужна какая то внутренняя часть, то постарайтесь обеспечить доступ через фасад (границу модуля)

Комментариев нет:

Отправить комментарий