Software Architect · Модуль 08

Код можно переписать за квартал. Данные, контракты и исторические ошибки иногда живут всю жизнь продукта.

Invariants · normalization · migration · OLTP · OLAP

§ 01

Модель данных должна защищать смысл бизнеса, а не только удобно обслуживать текущий экран.

Данные стареют медленнее кода

Интерьер можно поменять быстро. Неправильно залитый фундамент остаётся с домом надолго.

Фреймворк, UI и даже язык программирования могут смениться. Но таблицы, события, ключи, исторические записи и внешние отчёты продолжают жить. Поэтому data model — одно из самых дорогих архитектурных решений.

Архитектор должен явно понимать инварианты: что всегда должно быть истинно. Например: заказ не может быть оплачен без payment intent; проводка не может исчезнуть; баланс не должен стать отрицательным без разрешённого overdraft.

Нормализация и денормализация — не религия

Архив хранит оригиналы документов. Витрина делает копии для быстрого просмотра. Обе формы нужны, но для разных задач.

Нормализация снижает дублирование и риск рассинхрона. Денормализация ускоряет чтение и упрощает read model. В OLTP-системах важны транзакции и консистентность текущего состояния. В OLAP важны аналитические запросы, история и агрегации.

Ошибка — пытаться одной моделью идеально обслужить и checkout, и realtime dashboard, и бухгалтерский отчёт. Часто нужна source-of-truth модель и отдельные projection/read models.

§ 02

Хорошая модель делает невозможные состояния невозможными или хотя бы явно незаконными.

Пример: pricing snapshot в заказе

Чек в магазине хранит цену на момент покупки, даже если завтра товар подорожает.

Order хранит не только product_id, но и snapshot цены, валюты, налогов, скидки и названия на момент покупки. Catalog может измениться, но исторический заказ остаётся корректным.

Это небольшая денормализация, которая защищает бизнес-смысл. Без неё отчётность и поддержка клиентов станут зависеть от текущего состояния каталога.

Антипример: универсальная таблица events_json

Склад без полок кажется гибким: всё можно положить куда угодно. Потом никто не находит нужное.

Команда складывает все бизнес-сущности в одну таблицу с JSON, потому что «так гибче». Сначала быстро. Потом появляются миграции внутри JSON, неявные схемы в коде, медленные запросы, отсутствие constraints и невозможность понять, какие данные валидны.

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

Самопроверка
  • Какие инварианты защищает база, а какие только код? - Какие данные являются source of truth? - Что будет с историей при изменении справочника? - Как выглядит безопасная миграция этой модели?