Software Architect · Модуль 08
Код можно переписать за квартал. Данные, контракты и исторические ошибки иногда живут всю жизнь продукта.
Invariants · normalization · migration · OLTP · OLAP
Модель данных должна защищать смысл бизнеса, а не только удобно обслуживать текущий экран.
Данные стареют медленнее кода
Интерьер можно поменять быстро. Неправильно залитый фундамент остаётся с домом надолго.
Фреймворк, UI и даже язык программирования могут смениться. Но таблицы, события, ключи, исторические записи и внешние отчёты продолжают жить. Поэтому data model — одно из самых дорогих архитектурных решений.
Архитектор должен явно понимать инварианты: что всегда должно быть истинно. Например: заказ не может быть оплачен без payment intent; проводка не может исчезнуть; баланс не должен стать отрицательным без разрешённого overdraft.
Нормализация и денормализация — не религия
Архив хранит оригиналы документов. Витрина делает копии для быстрого просмотра. Обе формы нужны, но для разных задач.
Нормализация снижает дублирование и риск рассинхрона. Денормализация ускоряет чтение и упрощает read model. В OLTP-системах важны транзакции и консистентность текущего состояния. В OLAP важны аналитические запросы, история и агрегации.
Ошибка — пытаться одной моделью идеально обслужить и checkout, и realtime dashboard, и бухгалтерский отчёт. Часто нужна source-of-truth модель и отдельные projection/read models.
Хорошая модель делает невозможные состояния невозможными или хотя бы явно незаконными.
Пример: pricing snapshot в заказе
Чек в магазине хранит цену на момент покупки, даже если завтра товар подорожает.
Order хранит не только product_id, но и snapshot цены, валюты, налогов, скидки и названия на момент покупки. Catalog может измениться, но исторический заказ остаётся корректным.
Это небольшая денормализация, которая защищает бизнес-смысл. Без неё отчётность и поддержка клиентов станут зависеть от текущего состояния каталога.
Антипример: универсальная таблица events_json
Склад без полок кажется гибким: всё можно положить куда угодно. Потом никто не находит нужное.
Команда складывает все бизнес-сущности в одну таблицу с JSON, потому что «так гибче». Сначала быстро. Потом появляются миграции внутри JSON, неявные схемы в коде, медленные запросы, отсутствие constraints и невозможность понять, какие данные валидны.
JSON полезен для расширяемых атрибутов и событий, но не должен заменять модель там, где есть строгие инварианты.
- Какие инварианты защищает база, а какие только код? - Какие данные являются source of truth? - Что будет с историей при изменении справочника? - Как выглядит безопасная миграция этой модели?