Что такое паттерн разделения на чтение и запись
Что проверяют
Понимаете ли вы, что разделение чтения и записи это решение про модели, а не про технологии, и трезво ли смотрите на его цену. В Go тот же принцип встречается на трёх этажах, и сильный ответ начинается с вопроса, о каком именно идёт речь.
Как отвечать
Разведите уровни сразу. Внутри процесса это sync.RWMutex: много читателей одновременно либо один писатель. На уровне базы это реплики для чтения, которые снимают нагрузку с основного узла ценой отставания. На уровне архитектуры сервиса это CQRS, где у команд и запросов разные модели.
CQRS в определении: команда меняет состояние и не возвращает данные, запрос возвращает данные и ничего не меняет, причём модели у них свои. Запись живёт нормализованной схемой и следит за инвариантами, чтение отдаёт готовое представление под конкретный экран.
type Commands interface {
CreateOrder(ctx context.Context, in NewOrder) (OrderID, error)
}
type Queries interface {
OrderCard(ctx context.Context, id OrderID) (OrderCardView, error)
}Два интерфейса и две реализации поверх одной базы это уже CQRS. Отдельное хранилище для чтения, проекции и шина между ними это следующий шаг, за который платят согласованностью.
Назовите цену честно: отложенная согласованность, дублирование кода и моделей, инвалидация проекций, необходимость перестраивать их после ошибки.
Где спотыкаются
Считают CQRS синонимом событийного источника и обязательной второй базы. Это независимые решения, и чаще всего разделение моделей прекрасно живёт на одной базе.
Игнорируют отставание. Пользователь сохранил заказ, интерфейс тут же читает его из реплики или проекции и показывает старую версию. Лечится чтением после записи с основного узла, возвратом результата прямо из команды или ожиданием нужной версии.
Подменяют паттерн переименованием: разложили обработчики на чтение и запись по разным пакетам и считают, что внедрили CQRS. Смысл появляется только тогда, когда у чтения действительно своя модель, а не тот же самый тип структуры, что и у записи.