Перейти к основному содержимому

Моделирование данных

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

Почему это важно. Ошибка в модели — самая дорогая в исправлении, потому что к моменту, когда она начинает мешать, в проде уже лежат данные, уложенные по ней. Экран можно перерисовать за полдня; связь, которая должна была быть многие-ко-многим, — нельзя.

Что нужно понимать

  • Что представляет собой объект реального мира — независимо от экрана, на котором он показан
  • Какие связи один-к-одному, один-ко-многим, многие-ко-многим — и какие из них ещё поменяются
  • Что должно быть верно всегда и где именно это правило обеспечивается
  • Что хранится, а что вычисляется
  • Важна ли история или достаточно текущего состояния

Ключевые темы

Сущности и связи

  • Как выделять сущности из предметной области, а не из интерфейса
  • Кардинальность связей и цена ошибки в ней
  • Связующие таблицы и момент, когда связь заслуживает собственной сущности, потому что несёт данные
  • Обязательное и необязательное — и что на самом деле означает здесь null

Ограничения и инварианты

Правила, которым данные обязаны соответствовать, — где бы они ни проверялись.

  • Уникальность, внешние ключи, check-ограничения
  • Правила, которые может гарантировать база, и правила, доступные только приложению
  • Почему одно место, где правило гарантируется, лучше трёх мест, где оно проверяется

Нормализация и её пределы

  • Как убрать дублирование, чтобы факт хранился в одном месте
  • Когда денормализация — осознанное решение ради производительности
  • Как распознать схему, денормализованную случайно

Изменения со временем

  • Миграции и то, как писать их, чтобы они отработали на реальных данных
  • Мягкое удаление, журнал изменений, история событий
  • Версионирование модели, от которой уже зависят клиенты

Уровни

УровеньКак это выглядит
JuniorДобавляет поля и таблицы так, чтобы заработал экран, который сейчас перед ним.
MiddleВыделяет сущности из предметной области, не ошибается в кардинальности и полагается на ограничения, а не только на валидацию.
SeniorПредвидит, как модели придётся меняться, пишет миграции, безопасные для боевых данных, и понимает, когда денормализовать намеренно.

Практика

Для начала

  • Постройте модель от предметной области Возьмите фичу, описанную словами, и выведите из неё сущности до того, как нарисуете хоть один экран.

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

  • Добавьте настоящее ограничение Перенесите в базу правило, которое сейчас проверяется в коде приложения.

Глубже

  • Напишите миграцию, которая не может потерять данные Разделите таблицу или смените тип колонки на уже существующих данных.

  • Смоделируйте историю Превратите то, что хранит только текущее состояние, в то, что умеет ответить на вопрос «а как это выглядело месяц назад».

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

Проверьте себя

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

Ресурсы

  • Designing Data-Intensive Applications — книга Мартина Клеппмана и основной источник о том, как на самом деле взаимодействуют модели данных, хранение и согласованность. Одна вторая глава уже окупает потраченное время.
  • PostgreSQL: Data Definition — что настоящая база умеет гарантировать за вас. Прочитайте главу про ограничения, даже если никогда не пишете SQL руками.
  • Patterns of Enterprise Application Architecture catalog — словарь для разговора о том, как встречаются объекты и таблицы, от Active Record до Data Mapper. Краткое описание каждого паттерна доступно бесплатно.
  • Database normalization — простой справочник по нормальным формам. Стоит один раз прочитать внимательно, чтобы потом отличать осознанную денормализацию от случайной.
  • Serverpod: database models — как всё это выглядит именно в Dart, включая связи и генерируемый код.