Я думаю, что другие ответы смешивают CQRS в целом и возможную согласованность в частности. Пользовательский интерфейс на основе задач очень подходит для CQRS, но он не решает проблему с согласованной моделью чтения.
Во-первых, я хотел бы оспорить ваше утверждение:
Пользователи нажимают кнопку «Сохранить» и мгновенно видят результат ... с возможной последовательностью это невозможно.
Что ты этим считаешь? Почему невозможно сразу увидеть результат ? Я думаю, что проблема здесь в вашем определении результата .
Результатом любого действия является то, что это действие было выполнено. Есть множество способов показать это! Это зависит от того, какое действие вы хотите выполнить. Примеры:
Отправка электронного письма: если пользователь ввел правильный адрес электронной почты, почти гарантировано, что действие будет успешно выполнено. Для предотвращения непредвиденных сбоев можно использовать долговременные очереди, поскольку такого рода действия не нужно выполнять синхронно. Так что вы просто говорите «электронная почта отправлена». Обычно вы видите такой ответ, когда просите сбросить пароль.
Обновите некоторую информацию в профиле пользователя: после того, как вы проверили новые данные на клиенте, скорее всего, команда тоже выполнится успешно, поскольку единственное, что может произойти, - ошибка базы данных (если вы используете базу данных). Опять же, даже это может быть смягчено с помощью длительных очередей. В этом случае вы просто показываете обновленное поле в той же форме. Хорошей практикой для SPA является создание полного хранилища данных на стороне клиента, как это делает Redux. В этом случае вы можете безопасно обновить сервер, отправив команду, а также обновив хранилище на стороне клиента, в результате чего в пользовательском интерфейсе отобразятся последние данные. Отказ от ответственности: некоторые ответы называют эту технику «обманом пользователя», но я не согласен с этим определением.
Если у вас есть команды, склонные к ошибкам, вы можете использовать методы, которые уже описаны в других ответах, таких как веб-сокеты или события на стороне сервера, для обратной передачи ошибок. Это требует довольно много дополнительной работы. Вы также можете отправить команду и дождаться ответа или выполнить команды синхронно. Кто-то скажет: «Это не CQRS», но это будет просто еще одна догма, которую нужно оспорить. Обеспечение того, чтобы команда завершила выполнение в сочетании с предыдущим пунктом (хранилище данных на стороне клиента), будет хорошим решением.
Я не уверен, существует ли какой-либо метод 100% пуленепробиваемой проверки, который позволяет вам всегда показывать нестарелые данные из прочитанной модели. Я думаю, что это идет вразрез с принципами CQRS. Даже с событиями в реальном времени вы будете получать только события, которые указывают, что вы пишете, что модель была обновлена. Тем не менее, ваши прогнозы могли провалиться, и реакция на это - совсем другая история.
Однако я бы не стал так сильно концентрироваться на этом вопросе. Дело в том, что хорошо протестированные проекции и почти гарантированные команды будут работать очень хорошо. Для обработки ошибок в 90% случаев достаточно ручного или полуручного процесса для восстановления после этих ошибок. За последние 10% вы можете объединить общие сообщения об ошибках, выдаваемые с сервера: «извините, ваше действие XXX не удалось выполнить», и действия с высоким приоритетом могут иметь какой-то творческий процесс, но в действительности эти ситуации будут очень редкий.