Был у нас спор о том, нужно ли между двумя системами делать дополнительную синхронизацию: периодически сверять данные, чтобы не потерять сообщения. Одна сторона настаивала, что outbox гарантирует доставку, другая: а вдруг снова сломается.

Если коротко, outbox в одной транзакции пишет запись с бизнес-данными и запись события, а потом отправляет это событие до победного.

Мы спорили не про архитектуру. Мы спорили про инцидент. Его техническая часть была уже закрыта в системе: сообщение не может потеряться — оно либо в outbox, либо уже доставлено. А пока инцидент свежий в памяти, слово «надёжно» ничего не значит. Для человека, который видел, как теряются сообщения, «у нас есть outbox» звучит как «поверьте мне». Инцидент не закрыт в памяти, поэтому любой новый механизм воспринимается как заплатка на незажившую рану. Понял я это с опозданием.

Дополнительная синхронизация была не архитектурным решением. Она лечила страх, что система когда-то сломается.

Уже после обсуждения я вспомнил, что встречал подобное. В книге Марка Ричардса и Нила Форда «Фундаментальный подход к программной архитектуре» есть антипаттерн Frozen Caveman — «замороженный пещерный человек»:

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

Наш кейс был частным случаем этого. В итоге мы от синхронизации отказались, но обсуждение заняло слишком много времени. Как перевести такой страх в измеримую плоскость? На мой взгляд, стоило добавить метрику возраста самого старого недоставленного сообщения в outbox и алерт на неё. Тогда «а вдруг» пришлось бы показывать цифру, а не воспоминание.