Подтвердить что ты не робот

Опрос использования DTO с сохранением обслуживания и извлечением поведения из обновления

В области DDD мне нравится идея избегать геттеров и сеттеров, чтобы полностью инкапсулировать компонент, поэтому единственное взаимодействие, которое разрешено, - это взаимодействие, которое было построено поведением. Объединяя это с Event Sourcing, я могу получить хорошую историю того, что было сделано, и когда к компоненту.

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

  • ChangeDueDate(DateTime date)
  • ChangeDescription(string description)
  • AddTags(params string[] tags)
  • Complete()

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

Возвращаясь к службе REST, я вижу, что есть 3 варианта:

  • Сделать URL-адреса стиля RPC, например. http://127.0.0.1/api/tasks/{taskid}/changeduedate
  • Разрешить отправку многих команд в одну конечную точку, например:
    • URL: http://127.0.0.1/api/tasks/{taskid}/commands
    • Это будет принимать список команд, поэтому я мог бы отправить следующее в том же запросе:
      • ChangeDueDate команда
      • ChangeDescription команда
  • Сделать по-настоящему доступный глагол RESTful, и я создаю логику домена для извлечения изменений из DTO и, в свою очередь, перевод соответствующих релевантных событий, например:
    • URL: http://127.0.0.1/api/tasks/{taskid}
    • Я бы использовал глагол PUT для отправки DTO-представления задачи
    • После получения я могу дать DTO реальному объекту домена задачи через метод, который может быть вызван, UpdateStateFromDto
    • Затем это проанализировало dto и сравнило бы свойства сопоставления с его полями, чтобы найти различия, и могло бы иметь соответствующее событие, которое должно быть запущено, когда оно находит разницу с определенным свойством.

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

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

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

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

4b9b3361

Ответ 1

Я бы сказал, вариант 1. Если вы хотите, чтобы ваша служба была RESTful, тогда вариант 2 не является вариантом, вы будете туннелировать запросы.

POST /api/tasks/{taskid}/changeduedate легко реализовать, но вы также можете сделать PUT /api/tasks/{taskid}/duedate.

Вы можете создавать ресурсы контроллера, если хотите сгруппировать несколько процедур в один, например. POST /api/tasks/{taskid}/doThisAndThat, я бы сделал это на основе шаблонов использования клиентов.

Вам действительно нужно предоставить возможность вызывать любое количество "поведений" по одному запросу? (имеет значение вопрос?)

Если вы хотите перейти с опцией 3, я бы использовал PATCH /api/tasks/{taskid}, таким образом, клиенту не нужно включать всех членов в запрос, только те, которые нужно изменить.

Ответ 2

Определить термин: operation = command or query с точки зрения домена, например ChangeTaskDueDate(int taskId, DateTime date) - операция.

В REST вы можете сопоставлять операции с парами ресурсов и методов. Поэтому вызов операции означает применение метода к ресурсу. Ресурсы идентифицируются с помощью URI и описываются существительными, такими как задача или дата, и т.д. Методы определены в стандарте HTTP и являются глаголами, такими как get, post, put и т.д. Структура URI на самом деле не является означает что-либо для клиента REST, поскольку клиент имеет дело с машиносчитываемыми материалами, но для разработчиков упрощается внедрение маршрутизатора, генерация ссылок, и вы можете использовать его для проверки того, привязывали ли вы URI к ресурсам, а не к таким операциям, как RPC делает.
Итак, в нашем текущем примере ChangeTaskDueDate(int taskId, DateTime date) глагол будет change, а существительные task, due-date. Таким образом, вы можете использовать следующие решения:

  • PUT /api{/tasks,id}/due-date "2014-12-20 00:00:00" или вы можете использовать
  • PATCH /api{/tasks,id} {"dueDate": "2014-12-20 00:00:00"}.

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

Теперь это был очень простой пример, потому что это простой CRUD. С помощью не CRUD-операций вы должны найти правильный глагол и, возможно, определить новый ресурс. Вот почему вы можете сопоставлять ресурсы объектам только с помощью операций CRUD.

Возвращаясь к службе REST, я вижу, что есть 3 варианта:

  • Сделать URL-адреса стиля RPC, например. http://example.com/api/tasks/ {taskid}/changeduedate
  • Разрешить отправку многих команд в одну конечную точку, например:
    • URL: http://example.com/api/tasks/ {taskid}/commands
    • Это будет принимать список команд, поэтому я мог бы отправить следующее в том же запросе:
      • Команда ChangeDueDate
      • Команда ChangeDescription
  • Сделайте по-настоящему спокойный глагол доступным, и я создаю логику домена для извлечения изменений из dto и, в свою очередь, необходимых событий, например:
    • URL: http://example.com/api/tasks/ {taskid}
    • Я бы использовал глагол PUT для отправки DTO-представления задачи
    • После получения я могу дать DTO реальному объекту домена задачи через метод, который может быть вызван, UpdateStateFromDto
    • Затем это проанализировало бы dto и сравнило бы свойства соответствия с его полями, чтобы найти различия, и может иметь соответствующее событие, которое необходимо уволить, когда оно находит разницу с определенное свойство найдено.
  • Структура URI ничего не значит. Мы можем говорить о семантике, но REST очень отличается от RPC. Он имеет некоторые очень специфические ограничения, которые вы должны прочитать перед тем, как что-либо сделать.

  • У этой проблемы есть тот же самый вопрос, что и ваш первый ответ. Вам необходимо сопоставить операции с методами HTTP и URI. Они не могут путешествовать в теле сообщения.

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