ER-модель, кардинальности и уровни C4

ER-модель, кардинальности и уровни абстракции C4 — как показать, что вы умеете думать и о данных, и об архитектуре целиком.

ER-модель описывает, из каких сущностей состоят данные и как они связаны. C4 — способ показать систему на четырёх уровнях приближения, от контекста до кода, чтобы каждой аудитории досталась своя картинка.

Вопрос 1. Что такое ER-модель и как вы читаете кардинальности?

Что проверяют. Умеете ли вы переводить бизнес-правило в структуру данных и обратно. Кардинальность — это не украшение линии, а зафиксированное правило.

Связь читается с двух сторон, и обе стороны нужно проговаривать вслух:

ЗаписьКак читатьКак реализуется
1 : 1у клиента ровно один профиль настроеквнешний ключ с уникальным индексом
1 : Nу клиента много заказов, у заказа один клиентвнешний ключ на стороне «много»
N : Mу заказа много товаров, товар в многих заказахотдельная таблица-связка
0..1 : Nзаказ может быть без промокодавнешний ключ, допускающий NULL
1..* в заказе минимум одна позицияпроверка на уровне приложения или триггера

Самое важное на собеседовании — заметить, что связь «многие ко многим» почти никогда не бывает пустой: у неё есть собственные атрибуты. У связки «заказ — товар» это количество и цена на момент покупки. Ниже — исполнимый пример: создадим схему и убедимся, что связка хранит собственные данные.

CREATE TABLE customer (
  id      INTEGER PRIMARY KEY AUTOINCREMENT,
  name    TEXT NOT NULL,
  email   TEXT
);

CREATE TABLE product (
  id      INTEGER PRIMARY KEY AUTOINCREMENT,
  title   TEXT NOT NULL,
  price   REAL NOT NULL
);

CREATE TABLE "order" (
  id           INTEGER PRIMARY KEY AUTOINCREMENT,
  customer_id  INTEGER NOT NULL REFERENCES customer(id),
  created_at   TEXT NOT NULL,
  status       TEXT NOT NULL
);

-- таблица-связка N:M со СВОИМИ атрибутами
CREATE TABLE order_item (
  order_id     INTEGER NOT NULL REFERENCES "order"(id),
  product_id   INTEGER NOT NULL REFERENCES product(id),
  qty          INTEGER NOT NULL,
  price_at_buy REAL NOT NULL,
  PRIMARY KEY (order_id, product_id)
);

INSERT INTO customer (name, email) VALUES ('Анна', 'anna@example.com');
INSERT INTO product (title, price) VALUES ('Кофе', 500.0), ('Чайник', 3200.0);
INSERT INTO "order" (customer_id, created_at, status)
  VALUES (1, '2026-03-01', 'paid');
INSERT INTO order_item (order_id, product_id, qty, price_at_buy)
  VALUES (1, 1, 2, 450.0), (1, 2, 1, 3200.0);

-- цена в заказе зафиксирована и не зависит от текущей цены товара
SELECT c.name, p.title, oi.qty, oi.price_at_buy, p.price AS price_now
FROM "order" o
JOIN customer   c  ON c.id = o.customer_id
JOIN order_item oi ON oi.order_id = o.id
JOIN product    p  ON p.id = oi.product_id;

Запустите блок — в результирующей таблице будут две строки: «Анна, Кофе, 2, 450.0, 500.0» и «Анна, Чайник, 1, 3200.0, 3200.0».

Столбец price_at_buy отличается от price_now — ровно то бизнес-правило, о котором нужно спросить заказчика: «показывать в истории цену покупки или текущую?». В модели это одно поле, в разговоре — целое требование.

Вопрос 2. Расскажите про C4 — зачем нужны уровни?

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

  1. Уровень 1 — контекст (System Context). Наша система как один прямоугольник, вокруг — пользователи и внешние системы. Аудитория: бизнес, заказчик, новый сотрудник в первый день. Отвечает на вопрос «где мы в мире и с кем общаемся».
  2. Уровень 2 — контейнеры (Container). Разворачиваем систему на разворачиваемые единицы: веб-приложение, мобильное приложение, API, база данных, брокер сообщений. Указываем технологию и протокол связи. Аудитория: команда, архитектор, аналитик. Это самый полезный уровень для аналитика.
  3. Уровень 3 — компоненты (Component). Внутренности одного контейнера: модули и их ответственность. Аудитория: разработчики этого сервиса. Рисуется по необходимости.
  4. Уровень 4 — код. Классы и связи. На практике почти всегда генерируется из кода или не рисуется вовсе.
C4, уровень 2 (контейнеры) для интернет-магазина

[Покупатель] ──HTTPS──> (SPA, браузер, Vue)
                            │ JSON/HTTPS
                            ▼
                      (API заказов, Java)
                       │        │       │
             SQL/JDBC  │        │       │ AMQP
                       ▼        │       ▼
              [PostgreSQL]      │  [RabbitMQ] ──> (Сервис уведомлений)
                                │
                       HTTPS    ▼
                       [Платёжный шлюз — внешняя система]

Аналитику уровень контейнеров нужен как карта: по нему сразу видно, каких интеграций коснётся новая фича и с кем нужно согласовать контракт.

Вопрос 3. Логическая, концептуальная и физическая модель данных — в чём разница?

Короткий и точный ответ, который ценят: концептуальная — только сущности и связи, языком бизнеса, без атрибутов и типов; логическая — атрибуты, ключи, нормализация, но без привязки к СУБД; физическая — конкретные таблицы, типы данных, индексы, партиционирование под выбранную СУБД. Аналитик отвечает за первые две, физическую делает вместе с разработчиком или DBA.

Типичные ошибки кандидатов

  • Не проговаривают кардинальность с обеих сторон и теряют бизнес-правила вроде «заказ не может быть пустым».
  • Рисуют N:M без таблицы-связки и не замечают, что у связи есть собственные атрибуты.
  • Не различают уровни моделей и приносят бизнесу физическую схему с индексами.
  • Считают C4 «ещё одной нотацией» вместо способа подобрать уровень детализации под аудиторию.
  • Забывают историчность: цена, адрес, тариф меняются, и модель обязана решить, хранить ли значение на момент операции.

Как ответить кратко

ER-модель — это сущности, их атрибуты и связи с кардинальностями, причём кардинальность я всегда читаю с обеих сторон, потому что это записанное бизнес-правило: «в заказе минимум одна позиция» — уже требование. Связь многие-ко-многим разворачиваю в таблицу-связку и проверяю, есть ли у неё собственные атрибуты — количество, цена на момент покупки. Различаю концептуальную, логическую и физическую модели: первые две на мне, физическая — вместе с разработчиком. C4 использую, чтобы дать каждой аудитории свой масштаб: контекст для бизнеса, контейнеры для команды — этот уровень мне нужнее всего, потому что по нему видно, какие интеграции затронет фича.

Проверьте себя
1. Как реализуется связь «многие ко многим» между заказом и товаром?
AВнешним ключом в таблице заказа
BОтдельной таблицей-связкой, часто со своими атрибутами вроде количества и цены на момент покупки
CМассивом идентификаторов в поле заказа
DУникальным индексом по двум таблицам
2. Какой уровень C4 полезнее всего системному аналитику в повседневной работе?
AУровень 1 — контекст
BУровень 2 — контейнеры
CУровень 3 — компоненты
DУровень 4 — код
3. Чем логическая модель данных отличается от физической?
AЛогическая содержит атрибуты и ключи без привязки к конкретной СУБД, физическая — типы, индексы и особенности выбранной СУБД
BЛогическая рисуется в UML, а физическая — в BPMN
CЛогическая содержит только сущности и связи без атрибутов
DФизическая нужна только для NoSQL-баз