Охват к подписчикам
54,6%
ERR
Реакции к просмотрам
0,37%
99 на 21 постов
Пересылки к просмотрам
0,68%
181
Постов в день
0,7
всего 21
Где отзываются чаще
доля реакций к просмотрам- 10 авг.System Design: frontend Сегодня разберём задачку, которую реально дают на секции систем дизайн в Авито. Условие короткое: «спроектируй конструктор виджетов на JS-фреймворке» — штука, где из готовых блоков собираешь кусок интерфейса (карточку, баннер, секцию на выдаче) и выкатываешь пользователям. Первое, что приходит в голову — drag-n-drop: таскаешь блоки по канвасу, а на выходе он генерит React-компоненты. За полчаса набросал, вроде работает. И вот тут ты уже проиграл: ты сделал «редактор, который выплёвывает вёрстку», а задача была про систему, которой пользуются не только разработчики и которая живёт дольше одного релиза фронта. Дальше весь пост — как из первого прийти во второе. Начнем с вопросов, а не с кода Условие специально дают без требований: ждут, что ты сам очертишь границы. Так что не лезь в код, сначала спроси. И главный вопрос один: кто собирает интерфейс в этом конструкторе и где потом рендерится результат. Звучит организационно, а на деле именно он задаёт всю архитектуру — сейчас увидишь как. Идём за этим вопросом Скорее всего дадут такой ответ(тут зависит от интервьюера конечно же, в какую степь он захочет уйти): собирать интерфейс часто будет не разработчик, а контент-менеджер. А результат должен приезжать не только на веб, но и на iOS с Android - и без релиза приложения. И это меняет всё: JS в стор мгновенно не докатишь, нативную вёрстку из React не соберёшь. Значит выход конструктора в принципе не может быть кодом. Отсюда рождается ядро всей задачи: конструктор не генерит вёрстку, он собирает её описание — сериализуемое дерево, JSON: какие виджеты, в каком порядке, с какими параметрами. А рисует это дерево отдельный рендер-движок, свой на каждой платформе. Вёрстка тут — данные, а не код. Называется это Backend-Driven UI; в Авито ровно ради этого построили движок Beduin. Придёшь к этому сам — ответ уже не джуна, а если и назвать в качестве примера известную реализацию твоей идеи, то это +реп сразу. Раз вёрстка — это данные Дальше всё вытекает из этой мысли. Виджет — независимый переиспользуемый блок с контрактом: строго типизированные параметры, у каждого свой тип и обязательность. И первый жирный плюсик: форму настройки не пишем руками под каждый блок, а генерим из контракта. Разработчик зарегистрировал виджет в каталоге, описал параметры — конструктор сам построил форму. Иначе на сотне виджетов утонешь в формочках. У Авито это так и устроено в их Bricks — привести известную реализацию к своим мыслям всегда +реп. Где сыпятся Все грабли — из той же мысли «это данные». Забыл про неё — провалился. Наверное, самое тонкое место - превью. Блок, который контент-менеджер видит в редакторе, должен рендериться по тем же правилам, что и прод у юзера — из того же описания и тем же рендером, а не отдельным мокапом на React. Иначе разойдутся: собрал красиво, опубликовал, а у юзера поехало. Никакого eval — это прямое следствие того, что описание есть данные. JSON пришёл из админки, где сидит не разработчик: валидируем по схеме (те ли типы, на месте ли обязательные поля, разрешённый ли виджет), но не исполняем. Начнёшь evalить — получишь дыру в безопасности и падение на первом же кривом вводе. И то, на чём спотыкаются новички: не перерисовывай весь канвас на каждое изменение. Поменяли цвет у кнопки — обнови только кнопку. Иначе на большом макете редактор залагает на каждое нажатие. Что тут на самом деле проверяют Всё сводится к одному: понимаешь ли ты, что редактор с блоками — самая маленькая часть задачи. Собрать вёрстку из виджетов умеет и джун, это верхушка. А спроектировать надо то, что под ней: как это описание хранить и версионировать, доставлять на веб и обе мобилки, подтягивать в блоки живые данные, катить без релиза и откатывать, если сломается. Задал один вопрос «кто собирает и где рендерится» — и вся эта система развернулась сама. В следующем посте — задача от Яндекса, которую дают бэкендерам! Кстати, если хотите оставаться в тренде айти рынка и его требований, то советую наши курсы старт, на который мы продлили финальные скидки на 24 часа. ➡️ Записаться Подписаться: @codeof_art Вступить в чатик: @code_of_art1,41%
- 10 авг.без подписи0,79%
- 2 авг.System Design: backend Обещали разобрать бэк - делаем. Задачка с собеса в Сбере: нужно передавать файлы большого размера. Через мессенджер не выйдет, упрёмся в лимиты, значит либо торрент, либо поднимать свой сервер, либо что-то ещё. Как спроектируешь? Стоит начать не идти в лоб решать, а задать парочку вопросов, например я начал бы с такого: отправитель и получатель должны быть онлайн одновременно? Ну и попутно выясняем размер файлов, один получатель или тысячи качают одно и то же, сколько файл живёт и не корпоративная ли это сеть - потому что в корпоративной сети половина P2P просто не взлетит. Дальше развилка, ради которой задачу и дают. Можно пойти в P2P, когда файл льётся напрямую между участниками, а мы храним только метаданные. Мы не платим за хранение и за исходящий трафик, и чем популярнее файл, тем быстрее раздача, потому что получатели сами становятся источниками. Но обе стороны обязаны быть онлайн одновременно, придётся возиться с NAT и фаерволами, а фолбэк на релей - это уже снова наш сервер и наш трафик. Можно пойти централизованно: отправитель залил, получатель забрал когда захотел, никто никого не ждёт, но мы платим за хранение и, главное, за исходящий трафик, который тут и будет основной статьёй расходов. А в проде почти всегда получается гибрид, где метаданные, авторизация и сигналинг идут через наш сервер, а данные - напрямую между клиентами, где это возможно. Вот эту мысль и надо озвучить: выбор определяется требованиями. Что бы ты ни выбрал, файл целиком одним куском не гоняем никогда, режем на чанки. Отсюда сразу берётся возобновляемость - оборвалась сеть на N гб, дослали недостающие куски, а не начали всё сначала. Берётся параллельность, потому что несколько чанков льются одновременно и утилизируют канал. Берётся дельта-передача: правка внутри десятигигабайтного видео превращается из десяти гигабайт трафика в пару десятков мегабайт. Считаем хеш каждого чанка — и получаем дедупликацию, когда один и тот же файл, залитый сотней людей, лежит в единственном экземпляре, и заодно контроль целостности, когда битый кусок видно сразу и перекачивается только он. По хранению главное не смешивать вещи в кучу. В базе лежит запись о файле и ссылки на чанки, сами чанки - в объектном хранилище. И клиент заливает и качает напрямую туда по подписанной ссылке с ограниченным сроком жизни, минуя наши приложения, потому что если ты пропустишь пятьдесят гигабайт через свой бэкенд, ты его положишь. Наш сервис только выдаёт ссылку и пишет метаданные, а раздача идёт через CDN с поддержкой range-запросов, чтобы качалка умела докачивать. И главное, что стоит понимать про эту задачу. Интервьюеру в общем-то всё равно, что ты в итоге выбрал - торрент, свой сервер или гибрид. Ему важно, назовёшь ли ты условие, при котором выбрал бы другое. Пока ты рассуждаешь "раздача на тысячи получателей — значит P2P окупается, а тут передача один на один и получатель офлайн - значит хранилище", ты проходишь секцию. Как только не рассматриваешь другое решение при других вводных, а стоишь на одном и том же, то это сильно режет твои шансы на успешное прохождение собеса. Подписывайтесь на канал и вступайте в чатик, товарищи, так вы не пропустите новый контент! Подписаться: @codeof_art0,77%
- 18 июл.Товарищи, мы обновили линейку СТАРТ и открываем новый набор! 🚀 Мы переработали программы: обновили темы, добавили новые кейсы и вопросы с реальных собеседований, усилили практику и запустили полноценный карьерный блок. Если раньше упор был только на технические навыки, то теперь на курсе вы также научитесь: — составлять сильное резюме; — презентовать свой опыт, даже если коммерческой работы не было; — искать вакансии и понимать, куда лучше откликаться; — проходить HR-этапы и уверенно чувствовать себя на всех интервью. Открываем набор сразу на 4 направления: - Аналитика - Алгоритмы - Backend - Машинное обучение 📎Кому подойдет СТАРТ? Тем, кто: — готовится к первой работе и хочет получить системную базу; — уже проходит собеседования, но чувствует пробелы; — хочет попробовать направление на практике, прежде чем идти глубже; — хочет за лето прокачаться и выйти на рынок уже с готовым портфолио. Что будет на курсах? ➡️Аналитика Освоим SQL, продуктовые метрики, дашборды и A/B-тесты. В качестве пет-проекта пройдете полный цикл АВ тестирования — от запроса в БД до презентации результатов. Именно так работает аналитик. ➡️Алгоритмы Разберем всё, что действительно спрашивают на технических интервью: структуры данных, графы, динамическое программирование, деревья, теория чисел и многое другое. Закроем фундамент для алгособеседований и контестов. ➡️Backend Изучим архитектуру приложений, базы данных, Docker, gRPC и современные подходы к разработке. Итоговый пет-проект — полноценный сервис аналитики и прогнозирования цен криптовалют. ➡️Machine Learning Метрики качества, классические алгоритмы, бустинг, нейронные сети и Transformer. Пет-проект — система кредитного скоринга. Без искусственных задач вроде «обучи свою LLM», только то, с чем реально сталкивается ML-инженер в начале карьеры. Участникам курса также доступны: 🔵разбор контеста донабора Т-банк, стажировки в Яндекс, Авито буткемп DS (DS только на мл старт); 🔵mock-собеседования с обратной связью; 🔵закрытый банк вопросов с реальных интервью Яндекса, Т-Банка, Ozon, WB, Авито и других компаний; 🔵банк тестовых заданий и задач из бигтеха; 🔵реферальную рекомендацию в бигтех после успешной защиты пет-проекта. Курс длится 6 недель. Программа построена так, чтобы успевать осваивать теорию, выполнять домашние задания и постепенно делать пет-проект без перегруза. Все это время рядом преподаватель и куратор, которые помогают разобраться со сложными темами и отвечают на вопросы. 🔊Подробную программу и стоимость курсов смотрите на сайте Дополнительные скидки: -500 ₽, если учились уже у нас на других курсах -500 ₽, если берете с другом Действует гарантия: прошел курс, выполнил все рекомендации, но не получил оффер — вернем деньги 📌Для вопросов и записи на курс напишите менеджеру0,71%
- 24 июл.ИИ ВСЕХ ЗАМЕНИТ! ЧТО ДЕЛАТЬ? По результатам нашего опроса, 50% считает, что первые с рынка уйдут бэкендеры. Ещё 39% голосуют за аналитиков, а ML-специалисты пока чувствуют себя увереннее всех — за них отдали всего 11%. Но кто на самом деле находится под угрозой? В эту субботу в 19:00 устроим дебаты про ИИ. Преподаватели наших направлений по ML, аналитике и backend попробуют доказать, почему именно их профессия переживёт развитие нейросетей, а работа коллег изменится первой. Обсудим: — какие задачи ИИ уже забирает у специалистов; — где нейросети пока не могут заменить человека; — какие навыки скоро станут бесполезными; — чему учиться сейчас, чтобы не остаться без работы через пару лет. Будет жаркий спор трёх специалистов с большим опытом, но с разными взглядами на будущее рынка. Ну а ведущий эфира - легендарный Михаил Абрамович 😎 📅 Суббота, 19:00 🔗 Ссылка будет за 2 часа до эфира и в нашем боте @Postupashkianalitycsbot0,63%
- 31 июл.Уточнил у кандидата работал ли он со скоринговыми моделями как "Ясасу Бибу" и "Цист Яна". Ответ убил. https://youtube.com/shorts/ccNWpP5grzg0,62%
- 4 авг.C какими айтишницами стоит строить отношения, а какие - ред флаг? В новом ролике разобрал все бигтехи по фактам: Яндекс, ВК, Т-банк, Озон, Сбер. Смотрим! Смотрим! И не говорите потом, что не предупреждал! https://www.youtube.com/shorts/d_lUVE5oo7A0,54%
- 30 июл.System Design: frontend Разберём реальную задачку, её дали мне на собес в Яндекс Поиск. Пользователь вбивает в поиск «2+2», в выдаче нужно показать блок-калькулятор с уже посчитанным ответом, отрисовка серверная. Как реализуешь? Есть соблазн сразу начать думать про кнопки и стейт, но помним что, калькулятор джун напишет за двадцать минут. Мы же решаем инженерную задачау про то, что мы делаем не страницу, а виджет внутри чужой страницы, и живём по её правилам. Первое, что стоит спросить у интервьюера - а какой процент людей вообще кликает по этому блоку. Вопрос наверное покажется тупым сначала, а на самом деле он решает всю архитектуру, и я к нему вернусь. Заодно уточняем, что считаем (обычный калькулятор или инженерный, в целом это пригодится для согласования контракта запроса), сколько ещё блоков на выдаче и какой у нас бюджет по размеру бандла. Дальше поток простой. Бэк поиска понимает, что запрос - это выражение, парсит его и считает на сервере, отдаёт готовый HTML с уже проставленным ответом. Юзер видит «4» до того, как загрузился хоть один килобайт нашего JS. Вот, собственно, ради этого здесь и нужен SSR. Потом виджет гидрируется и становится кликабельным, и с этого момента все вычисления живут на клиенте - бегать на сервер за каждым нажатием кнопки нельзя, это верный способ завалить секцию. Состояние приезжает с сервера и обязательно сериализуется в разметку, а не пересчитывается заново на клиенте, иначе поймаешь hydration mismatch и блок мигнёт при перерисовке. После гидрации стейт полностью локальный, виджет автономен. Контракт с бэком выдачи выглядит примерно как выражение, его нормализованный вид и результат, причём результат передаём строкой, а не числом - иначе можем потерять точность. И ошибки проговариваем отдельно: невалидное выражение, деление на ноль и переполнение это три разных состояния, а не одно «что-то пошло не так». Теперь возвращаемся к тому вопросу про клики. Ответ на него такой: подавляющее большинство вбили «2+2», увидели «4» и ушли, они никогда не нажмут ни одной кнопки. Так зачем мы им грузим и гидрируем интерактивный калькулятор? Гидрируем лениво, по первому взаимодействию - клику, наведению. До этого на странице лежит статичный HTML, который стоит ноль. Если это сказать на собесе, то это большой плюсик для тебя, ответ явно не джуна. Дальше добираем очки от интервьюера. Гидрируем независимо от остальной выдачи, чтобы наш виджет не утащил за собой SERP. Никакого eval ни на сервере, ни на клиенте - выражение пришло от пользователя, это недоверенный ввод, нужен нормальный парсер. Про eval интервьюер спросит почти наверняка, а если не спросит, скажи сам, +реп. Результат детерминирован, «2+2» всегда даёт «4», значит блок прекрасно кэшируется. Ну и резервируем высоту блока, чтобы выдача не прыгала, делаем настоящие кнопки вместо дивов с onclick и вешаем aria-live на результат, чтобы скринридер его озвучил. Сразу видно, что человек думает о доступности, тоже +реп гарантирован. Если коротко, проверяют здесь одно: понимаешь ли ты разницу между «отрендерить» и «сделать интерактивным», и умеешь ли не платить за интерактивность там, где она девяноста пяти процентам людей не нужна. Подписывайтесь на канал и вступайте в чатик, товарищи, так вы не пропустите новый контент! Подписаться: @codeof_art0,50%
- 28 июл.System Design Друзья, решили ввести новую рубрику, где будем разбирать задачки с секции систем-дизайна - и по фронту, и по бэку. Будет полезно скорее джунам и мидлам, которые еще набивают руку и готовятся к собесам на более высокую позицию. Начнём разбор задачек с фронта, и вот почему. На просторах интернета я часто натыкался на разборы систем дизайна по бэкенду - там уже всё разобрано вдоль и поперёк. А по фронту совсем тухло. Особенно мало такого контента на русском - за рубежом эта тема в ходу давно, и вот за последние года три-четыре все чаще проводят собесы такого формата и у нас. Так что дыру затыкаем в первую очередь там, но бэк тоже разберём, задачки уже в очереди. Но давайте поговорим для начала вообще как проходит эта секция для всех направлений. Что такое систем-дизайн вообще Это секция, где тебе дают намеренно расплывчатую задачу — "спроектируй ленту новостей/сервис для хранения сообщений пользователей в мессенджере" - и оценивают не финальную картинку, а то, как ты к ней пришёл. Правильного ответа здесь не существует, есть обоснованный выбор под ограничения. Поэтому если ты не задал ни одного уточняющего вопроса и сразу побежал рисовать - ты уже валишь секцию, каким бы красивым ни вышло решение. В целом структура данного собеса одинаковая и для фронта, и для бэка, ниже кратко разберем её. Собираем требования. Задаём вопросы. Что за продукт, кто пользователи, какие ключевые сценарии, какие ограничения. Делим на функциональные требования (что система должна уметь) и нефункциональные (скорость, надёжность, доступность, безопасность). Половина хорошего ответа на собесе - это правильно заданные вопросы в первые несколько минут, но тут главное не задать слишком много вопросов, иначе можно себя закопать легко, тут важно не распыляться. Затем рисуем верхнеуровневую архитектуру. Крупные блоки и как между ними течёт поток данных. Пока без деталей реализации - только скелет. Продумываем данные и состояние. Что где хранится и в каком виде. Определяем контракты. Как части системы общаются друг с другом: формат запросов и ответов, как приходят ошибки. Углубляемся и оптимизируем. Узкие места, пограничные кейсы, отказы. Именно здесь джун превращается в мидла на глазах у интервьюера. Что спрашивают у бэкендеров Главный вопрос, на который ты весь час отвечаешь: выдержит ли твое решение миллион пользователей и не потеряем ли мы данные, если что-то упадёт. Отсюда и специфика: прикидка сколько запросов в секунду, сколько данных в день, от этого зависит выбор хранилища, тонкости работы с бд, отказоустойчивость и еще очень много всего. Тут также стоит помнить, что можно наворотить сверх крутую систему, но она обойдется бизнесу в бешенные деньги, и вот одна из задач на этом собесе, это прийти к наиболее лучшему решению за наименьшие траты. Что по фронту Тут же начинаем с одного пользователя, а затем масштабируемся. Также стоит учитывать, что у юзеров может быть плохой инет, древний браузер и кирпич вместо телефона. Это тоже сильное влияет на итоговое решение. Что стоит обсудить на этой секции: контракт API, стратегия рендеринга (CSR / SSR / SSG, гидрация), работа с состоянием. Дальше - производительность (размер бандла, ленивая загрузка, и прочие вещи), UX-состояния, доступность и локализация. И только потом выбор методологии под проект и уже совсем в конце сами компоненты. Как видите, если начинать решать задачку в лоб с выстраивания компонентов, будет больно и никуда вы не уедете. Что общего И там, и там проверяют одно и то же: умеешь ли ты работать в условиях неопределённости, видишь ли компромиссы и можешь ли объяснить, почему выбрал именно это. Формулировка уровня «я взял такой подход из-за ограничения X, но если бы было условие Y — выбрал бы Z» показывает в тебе инженера. Что дальше по плану - разборы конкретных задач с реальных собесов, примерно раз в неделю. Надеюсь, зайдёт и вы поддержите новую рубрику! Подписывайтесь на канал и вступайте в чатик, товарищи, так вы не пропустите новый контент! Подписаться: @codeof_art0,48%
- 14 апр.Ментор+ Эта услуга для тех, кто хочет трудоустроиться уже сейчас без лишней головной боли и теории. Что мы обещаем Достигнуть ваши цели, такие как получить оффер на стажировку, получить оффер в Бигтех с грейдом не ниже вашего текущего. Мы обсуждаем сроки. Если мы не в состоянии достигнуть ваших целей, то мы сразу же вам об этом скажем и предложим альтернативу (расширим пул компаний). Что мы не обещаем Мы не можем обещать нереальных или почти нереальных результатов как "оффер на 500 тыс (стажер)". Мы не можем обещать попадание в конкретную компанию. Как мы достигаем цели? 1. Легенда Мы прорабатываем с вами легенду, которую вы должны выучить и озвучить на собеседовании: где работали, что делали и так далее. Составляем конкретно под вас резюме. Если вам нужно проработать легенду и составить резюме, но вы хотите проходить собеседования полностью самостоятельно, то это отдельная услуга. Она стоит 15 тысяч рублей. Для записи: @vice22821. 2. Прохождение собеседований Подбираем с вами вакансии, проходим с вами собеседования, сидя у вас на наушнике, проходим лайвкодинг с помощью удаленного доступа. Если вам разово нужен специалист, который поможет на собеседовании: посидит на наушнике или пройдет лайвкодинг с удаленного доступа, то это отдельная услуга. Ориентировочная цена 10 тыс за пол часа собеса. Для записи: @vice22821 3. Теоретические занятия Теоретические занятия в ментор+ не входят, ментор+ для тех, кому нужно трудоустройство. Если вам нужны знания, вам подойдут курсы. Если у вас непростая ситуация и требуется консультация специалиста, то это отдельная услуга. Она стоит 8 тыс в час. Для записи: @vice22821. Если вам нужно мок собеседование, то это отдельная услуга. Она стоит 8 тыс в час. Для записи @vice22821. Как записаться Написать @vice22821 со своим запросом. Мы обсудим насколько ваша цель достижима, сколько на это потребуется времени и готовы ли мы взяться за ваш заказ. Если вас все устроит, то начнем работать. Оплата ментор + Залог составляет 30 тыс. Уже после получения оффера нужно внести 1 месячную зарплату после вычета налогов. Что если не получится Если не получилось получить оффер по нашей вине (после собеседований в 5 компаний у вас нет оффера) в установленные сроки, то мы возвращаем вам залог. Если не получилось получить оффер по вашей вине (например, вы решили отказаться от сотрудничества) в установленные сроки, то залог не возвращается. Ответы на часто задаваемые вопросы 1. Сколько в среднем вся работа займет времени? Если с вашей стороны нет задержек (например, уехали в отпуск), то максим 6 месяцев. Обычно удается получить оффер за 3 месяца. 2. Есть ли сопровождение на испытательном сроке? Не входит в ментор+, отдельная услуга и обсуждается индивидуально.0,44%
- 21 янв.Задача на сравнение чисел в джаве public static void main(String[] args) { Integer stupidNum1 = 127; Integer stupidNum2 = 127; Integer stupidNum3 = Integer.parseInt("127"); Integer stupidNum4 = 128; Integer stupidNum5 = 128; Integer stupidNum6 = -129; Integer stupidNum7 = -129; System.out.println(stupidNum1 == stupidNum2); System.out.println(stupidNum1 == stupidNum3); System.out.println(stupidNum4 == stupidNum5); System.out.println(stupidNum6 == stupidNum7); } Что будет выведено на экран при сравнении этих чисел? Результат: true true false false Объяснение: В джаве значения в диапазоне от -128 до 127 включительно хранятся в Integer кэше. Если инициализируется переменная со значением в указанном диапазоне, объект из кэша будет использован повторно => одна и та же ссылка на один и тот же объект. Если значение не входит в диапазон, создаётся новый объект в куче, и при проверке на равенство через "==" сравниваться будут ссылки на разные объекты. При создании значения через parseInt(): возвращается примитив int -> автоупаковка в Integer -> генерация вызова valueOf(), который проверяет, находится ли значение в диапазоне кэша, и либо возвращает кэшированный объект, либо создаёт новый объект типа Integer. В общем, помните об этом, но сравнивайте числа через equals(), чтобы не заморачиваться. @codeof_art0,43%
- 15 авг.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_art0,40%