TGViewer
Art of Code Art of Code @codeof_art · 2.18K subscribers
Post #311 2.9K
System Design: backend

Задача с реального собеса Яндекса. Условие: приходит уведомление — id, тип (EMAIL/SMS/PUSH), получатель, текст. У получателя есть разрешённые каналы и блок-лист отправителей. Нужно отфильтровать уведомление и не отправить дубль, если такое же уже было за последние 24 часа. Хранилище реализовывать не надо — только контракты и логика. Погнали.

Понятное дело, что мы уже люди опытные и не побежим писать код, думать над DTO — мы сразу будем думать над системой проверок уведомлений. Для этого сначала нужно понять, какой информации нам не хватает.

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

Например, что значит «такое же»? «Ваш заказ №123 готов» и «Ваш заказ №124 готов» — дубль или нет? А если одно пришло по EMAIL, а второе по SMS?

Поэтому уточняем:
* дедуп общий для всех каналов или отдельный;
* что именно считается одинаковым уведомлением;
* что считается успешной отправкой;
* какие ожидаются RPS.

Но главный вопрос один: где мы помним, что уже отправляли? Это относится к устройству хранилища, которое нам сказали не реализовывать, но без этой информации нам всё же не обойтись — дальше вернёмся к этому.

Ядро решения
Ключевая мысль: фильтрация — это цепочка независимых проверок, через которую уведомление либо проходит целиком, либо отсеивается на первом же несоответствии.

Не один раздутый if, а pipeline из мелких фильтров:
- канал разрешён у получателя;
- отправитель не в блок-листе;
- уведомление не дубль за последние 24 часа.

Первый же фильтр, сказавший «нет», отсекает уведомление — остальные не гоняем. Такую систему легко расширять: новый фильтр = ещё одно звено, а не правка портянки.

Возвращаемся к дедупликации
Дедуп за 24 часа означает, что система должна хранить след недавно отправленных уведомлений. Ключ вроде: recipient + type + id. А по нему — время отправки. Пришло новое — считаем ключ и смотрим, существует ли такой за последние 24 часа. И два неочевидных момента.

Первый — что именно входит в notificationIdentity. Сырый текст не всегда подходит: если в нём динамические данные, побайтовое сравнение может дать неправильную семантику. Поэтому сначала выясняем у интервьюера, что бизнес считает дублем. Второй — TTL. Записи должны сами протухать через 24 часа, иначе хранилище будет расти бесконечно.

Где сыпятся
Порядок фильтров: дешёвые и отсекающие проверки — вперёд. Канал и блок-лист — настройки. Дедуп — поход в стор. Глупо лезть в стор за дедупом, если уведомление и так отсечётся выключенным push.

Но есть ещё одна ловушка — гонка на дедупе. Поэтому check() и запись факта отправки должны быть атомарными. Например, через операцию tryReserve(key, ttl): первый запрос получает true, второй — false. А дальше интервьюер вполне может спросить: что будет, если мы зарезервировали уведомление, а внешний провайдер упал? Вот тут уже нужно отдельно определить семантику: защищаемся от повторного вызова сервиса или гарантируем отсутствие повторной доставки пользователю? Это разные задачи.

Контракты, а не реализация
Откуда берутся настройки и история отправок — прячем за интерфейсами: SettingsProvider, HistoryStore, и неважно, Redis там, PostgreSQL или внешний сервис. На собесе мы проектируем логику, а не привязываемся к конкретному хранилищу.

Что тут на самом деле проверяют
Проверяют одно: видишь ли ты, что это не «класс Notification с четырьмя полями», а конвейер фильтров с памятью о недавних отправках. Красивые модели нарисует и джун — и утонет в них, не дойдя до логики. Инженер сразу думает: что проверяем → в каком порядке → где храним состояние → что считаем дублем → что произойдёт при гонке.

А дальше строит pipeline от дешёвых проверок к дорогим, прячет источники данных за контрактами и понимает, что дедупликация — это не просто get() в Redis.

Подписаться: @codeof_art
Вступить в чатик: @code_of_art
Telegram Art of Code По вопросам: @vice22821 Чат: @code_of_art
  • 🔥 7
  • 👍 2
  • 🏆 2
More from @codeof_art
  1. Sep 22, 2026Новый пост из серии про паттерны на реальном коде. Разбираем штуку, с которой рано или поз…
  2. Sep 21, 2026Полный цикл собесов в Яндекс (Бэкенд 2026) Сейчас студенты наших курсов под чутким сопрово…
  3. Sep 20, 2026❗️ Яндекс открыл Intern Week Offer на стажировку, где всего за неделю ты можешь получить о…
  4. Sep 19, 2026Товарищи, Поступашкам нужны контент мейкеры в основной канал по алгоритмам и другим дисцип…
  5. Sep 17, 2026System Design: backend Сегодня разберём задачу, которую мне давали на собесе в Яндекс. Шту…
  6. Sep 16, 2026В Яндекс без опыта с первого раза Товарищи, продолжаем рассказывать про наших талантливых…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →