Большинство инженеров говорят, что им нужна доставка сообщений exactly-once.
На практике они строят идемпотентность поверх доставки at-least-once.
Idempotency → безопасность на уровне приложения
Exactly-once → гарантия на уровне инфраструктуры
Идемпотентность = повторное выполнение одной и той же операции приводит к тому же результату.
(Например,
Exactly-once = система гарантирует, что каждое событие повлияет на состояние ровно один раз.
(Например, EOS в Kafka. Но даже в этом случае нужны идемпотентные продюсеры и транзакционные получатели данных, чтобы эта гарантия сохранялась.)
Настоящего exactly-once на сетевом уровне не существует.
В итоге вы всегда приходите либо к at-most-once, либо к at-least-once, а затем компенсируете это на более высоком уровне системы.
Практическое правило:
Если бизнес-логика находится под вашим контролем → закладывайте идемпотентность в систему.
Если вы рассчитываете, что инфраструктура решит эту задачу за вас → в продакшене быстро поймёте, почему это была плохая идея.
«Effectively exactly-once» — это доставка at-least-once плюс идемпотентная бизнес-логика.
Вот и всё. В этом и заключается вся суть.
👉 @BackendPortal
На практике они строят идемпотентность поверх доставки at-least-once.
Idempotency → безопасность на уровне приложения
Exactly-once → гарантия на уровне инфраструктуры
Идемпотентность = повторное выполнение одной и той же операции приводит к тому же результату.
(Например,
PUT /order/123. Повторная отправка запроса не спишет деньги с клиента ещё раз.)Exactly-once = система гарантирует, что каждое событие повлияет на состояние ровно один раз.
(Например, EOS в Kafka. Но даже в этом случае нужны идемпотентные продюсеры и транзакционные получатели данных, чтобы эта гарантия сохранялась.)
Настоящего exactly-once на сетевом уровне не существует.
В итоге вы всегда приходите либо к at-most-once, либо к at-least-once, а затем компенсируете это на более высоком уровне системы.
Практическое правило:
Если бизнес-логика находится под вашим контролем → закладывайте идемпотентность в систему.
Если вы рассчитываете, что инфраструктура решит эту задачу за вас → в продакшене быстро поймёте, почему это была плохая идея.
«Effectively exactly-once» — это доставка at-least-once плюс идемпотентная бизнес-логика.
Вот и всё. В этом и заключается вся суть.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3👍2🔥1🤔1
Стартап реализовал управление сессиями так:
Сессии хранятся в памяти с использованием стандартного хранилища
Одна функция отвечает за всё:
С одним сервером и 100 пользователями это работает нормально.
При 1 миллионе пользователей на 5 экземплярах сервера:
→ Пользователь входит в систему на Сервере 1
→ Следующий запрос попадает на Сервер 2
→ Сессия не найдена, пользователь разлогинен
→ Потребление памяти растёт, пока сервер не падает
→ Перезапуск сервера мгновенно разлогинивает всех пользователей
→ Нет возможности инвалидировать отдельные сессии
→ Горизонтальное масштабирование становится невозможным
Какие архитектурные ошибки здесь допущены и как бы вы переработали управление сессиями,
чтобы оно работало на 10 серверах с 10 миллионами одновременно подключённых пользователей?
Ответ:
😧 😧 😧
👉 @BackendPortal
Сессии хранятся в памяти с использованием стандартного хранилища
express-session.Одна функция отвечает за всё:
Проверка учётных данных
Сохранение данных пользователя в сессии в памяти
Использование сессии для всех проверок аутентификации
С одним сервером и 100 пользователями это работает нормально.
При 1 миллионе пользователей на 5 экземплярах сервера:
→ Пользователь входит в систему на Сервере 1
→ Следующий запрос попадает на Сервер 2
→ Сессия не найдена, пользователь разлогинен
→ Потребление памяти растёт, пока сервер не падает
→ Перезапуск сервера мгновенно разлогинивает всех пользователей
→ Нет возможности инвалидировать отдельные сессии
→ Горизонтальное масштабирование становится невозможным
Какие архитектурные ошибки здесь допущены и как бы вы переработали управление сессиями,
чтобы оно работало на 10 серверах с 10 миллионами одновременно подключённых пользователей?
Ответ:
Ошибка не в Express Session.
Ошибка в хранении сессий в памяти сервера.
1 сервер → работает.
10 серверов → случайные разлогины.
Перезапуск сервера → все пользователи разлогинены.
Используйте Redis или stateless JWT для распределённой аутентификации.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9
Большинство разработчиков слышали про Bloom Filter.
Но гораздо меньше людей знают про Cuckoo Filter — структуру данных, которая отвечает всего на один вопрос:
1/ Представьте платёжный сервис, который получает миллионы запросов в день.
Перед обработкой платежа нужно проверить:
Можно сходить в базу. Можно проверить через Redis. Оба варианта работают.
Оба добавляют задержки и расходы.
2/ Здесь появляется Cuckoo Filter.
Это вероятностная структура данных для сверхбыстрой проверки наличия элемента.
Ответ может быть только таким:
- Точно отсутствует
- Вероятно присутствует
И всё это с очень небольшим потреблением памяти.
3/ Вместо хранения полного ключа вроде:
фильтр сохраняет короткий fingerprint:
За счёт этого память расходуется гораздо эффективнее.
4/ Схема работы выглядит так:
Полный объект не хранится.
Только его компактный отпечаток.
5/ Что делать, если оба бакета заняты?
Фильтр выбрасывает один из существующих fingerprint и переносит его в альтернативный бакет.
Этот механизм называется Cuckoo Hashing.
6/ Откуда название? От кукушки.
Кукушка подбрасывает яйца в чужие гнёзда.
Cuckoo Filter делает примерно то же самое: новый fingerprint может вытеснить старый, чтобы занять его место.
7/ Основные операции:
✅ Insert → O(1)
✅ Lookup → O(1)
✅ Delete → O(1)
В отличие от Bloom Filter, здесь есть нормальная поддержка удаления.
8/ Где это используют?
• идемпотентность API
• платёжные системы
• дедупликация событий в Kafka
• защита от cache penetration
• антифрод-системы
• стриминговые платформы
• CDN-инфраструктура
9/ Bloom Filter:
❌ удалять элементы нельзя
Cuckoo Filter:
✅ поддерживает удаление
✅ часто требует меньше памяти
✅ обеспечивает быстрые проверки
10/ Когда стоит использовать?
Если:
• память ограничена
• система работает в большом масштабе
• нужны быстрые membership-checks
• небольшой процент false positive допустим
11/ Когда не стоит использовать?
❌ нужны абсолютно точные ответы
❌ нужно хранить сами данные
❌ false positive недопустимы
Тогда берите базу данных или Redis.
12/ Если вашей системе нужно ответить только на вопрос:
Не факт, что нужен ещё один запрос к базе.
Возможно, достаточно одного Cuckoo Filter.
👉 @BackendPortal
Но гораздо меньше людей знают про Cuckoo Filter — структуру данных, которая отвечает всего на один вопрос:
«Я уже видел этот элемент раньше?»
1/ Представьте платёжный сервис, который получает миллионы запросов в день.
Перед обработкой платежа нужно проверить:
«Это новый запрос или дубликат?»
Можно сходить в базу. Можно проверить через Redis. Оба варианта работают.
Оба добавляют задержки и расходы.
2/ Здесь появляется Cuckoo Filter.
Это вероятностная структура данных для сверхбыстрой проверки наличия элемента.
Ответ может быть только таким:
- Точно отсутствует
- Вероятно присутствует
И всё это с очень небольшим потреблением памяти.
3/ Вместо хранения полного ключа вроде:
user123456789
фильтр сохраняет короткий fingerprint:
10110110
За счёт этого память расходуется гораздо эффективнее.
4/ Схема работы выглядит так:
Элемент
↓
Хеширование
↓
Fingerprint
↓
2 возможных бакета
↓
Сохранение fingerprint
Полный объект не хранится.
Только его компактный отпечаток.
5/ Что делать, если оба бакета заняты?
Фильтр выбрасывает один из существующих fingerprint и переносит его в альтернативный бакет.
Этот механизм называется Cuckoo Hashing.
6/ Откуда название? От кукушки.
Кукушка подбрасывает яйца в чужие гнёзда.
Cuckoo Filter делает примерно то же самое: новый fingerprint может вытеснить старый, чтобы занять его место.
7/ Основные операции:
✅ Insert → O(1)
✅ Lookup → O(1)
✅ Delete → O(1)
В отличие от Bloom Filter, здесь есть нормальная поддержка удаления.
8/ Где это используют?
• идемпотентность API
• платёжные системы
• дедупликация событий в Kafka
• защита от cache penetration
• антифрод-системы
• стриминговые платформы
• CDN-инфраструктура
9/ Bloom Filter:
Cuckoo Filter:
10/ Когда стоит использовать?
Если:
• память ограничена
• система работает в большом масштабе
• нужны быстрые membership-checks
• небольшой процент false positive допустим
11/ Когда не стоит использовать?
Тогда берите базу данных или Redis.
12/ Если вашей системе нужно ответить только на вопрос:
«Я уже видел это раньше?»
Не факт, что нужен ещё один запрос к базе.
Возможно, достаточно одного Cuckoo Filter.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍1
Если пишете код через Claude Code, очень советую поставить Trellis.
Без шуток, это один из самых полезных плагинов для Claude Code, которые я видел.
Многие говорят, что AI-кодинг нестабилен. Но часто проблема не в самом Claude. Проблема в том, что каждый новый запуск начинается как первый день на работе: снова объясняешь контекст проекта, снова описываешь требования, снова напоминаешь кодстайл, снова рассказываешь, на чём остановился в прошлый раз.
Trellis решает это довольно элегантно.
Он создаёт в проекте папку
По сути, это что-то вроде долговременной памяти для проекта.
И речь не про очередной шаблон промпта. Trellis добавляет полноценный workflow: планирование → реализация → проверка → сохранение накопленных знаний обратно в проект.
Особенно полезно для тех, кто:
• ведёт долгосрочные проекты через Claude Code
• устал постоянно восстанавливать контекст
• работает с большими кодовыми базами
• хочет, чтобы ИИ вёл себя больше как участник команды, а не как чат с короткой памятью
Без Trellis Claude Code напоминает очень сильного разработчика, который каждый день забывает, что делал вчера.
С Trellis уже появляется ощущение, что у проекта появилась собственная память.
https://github.com/mindfold-ai/Trellis
👉 @BackendPortal
Без шуток, это один из самых полезных плагинов для Claude Code, которые я видел.
Многие говорят, что AI-кодинг нестабилен. Но часто проблема не в самом Claude. Проблема в том, что каждый новый запуск начинается как первый день на работе: снова объясняешь контекст проекта, снова описываешь требования, снова напоминаешь кодстайл, снова рассказываешь, на чём остановился в прошлый раз.
Trellis решает это довольно элегантно.
Он создаёт в проекте папку
.trellis/, где хранит требования, стандарты, задачи, прогресс и историю работы. Когда Claude Code запускается снова, ему не нужно начинать с чистого листа. Он читает накопленный контекст, понимает текущее состояние проекта и продолжает работу с того места, где остановился.По сути, это что-то вроде долговременной памяти для проекта.
И речь не про очередной шаблон промпта. Trellis добавляет полноценный workflow: планирование → реализация → проверка → сохранение накопленных знаний обратно в проект.
Особенно полезно для тех, кто:
• ведёт долгосрочные проекты через Claude Code
• устал постоянно восстанавливать контекст
• работает с большими кодовыми базами
• хочет, чтобы ИИ вёл себя больше как участник команды, а не как чат с короткой памятью
Без Trellis Claude Code напоминает очень сильного разработчика, который каждый день забывает, что делал вчера.
С Trellis уже появляется ощущение, что у проекта появилась собственная память.
https://github.com/mindfold-ai/Trellis
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
GitHub - mindfold-ai/Trellis: The best agent harness.
The best agent harness. Contribute to mindfold-ai/Trellis development by creating an account on GitHub.
💊3
Большинство команд решают дублирующиеся API-запросы через отключение кнопки Submit.
Но это не идемпотентность.
Пользователь может:
• обновить страницу
• повторить запрос после таймаута
• открыть несколько вкладок
• отправить тот же запрос ещё раз
Для legacy-системы мы используем такую схему:
Флоу:
Ещё мы используем Cuckoo Filter как быстрый lookup-слой, чтобы снизить количество обращений к базе.
Главный вывод:
Cuckoo Filter ≠ идемпотентность
Unique Request ID + persistent store = идемпотентность
Фильтр оптимизирует производительность.
База данных гарантирует корректность.
👉 @BackendPortal
Но это не идемпотентность.
Пользователь может:
• обновить страницу
• повторить запрос после таймаута
• открыть несколько вкладок
• отправить тот же запрос ещё раз
Для legacy-системы мы используем такую схему:
React → UUID Request ID → Node API → MongoDB Unique Index → Legacy BackendФлоу:
React генерирует UUID для каждого запроса.
Node проверяет Request ID в MongoDB.
Если запись найдена — возвращаем существующий результат.
Если записи нет — обрабатываем запрос.
Сохраняем статус: PROCESSING, COMPLETED, FAILED.
Ещё мы используем Cuckoo Filter как быстрый lookup-слой, чтобы снизить количество обращений к базе.
Главный вывод:
Cuckoo Filter ≠ идемпотентность
Unique Request ID + persistent store = идемпотентность
Фильтр оптимизирует производительность.
База данных гарантирует корректность.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3
Многие знают Kafka, RabbitMQ или SQS.
Но очереди сообщений гораздо проще и гораздо опаснее, чем кажется.
Практически за каждой масштабируемой системой стоит очередь.
И за многими крупными инцидентами тоже.
Базовые понятия:
• Queue — очередь сообщений, обычно работающая по принципу FIFO (First In, First Out)
• Producer — отправляет сообщения в очередь
• Consumer — читает и обрабатывает сообщения
• Broker — управляет очередями (Kafka, RabbitMQ, SQS)
• ACK — подтверждение успешной обработки сообщения
• DLQ (Dead Letter Queue) — очередь для сообщений, которые не удалось обработать
• Idempotency — возможность безопасно обработать сообщение повторно без побочных эффектов
• Visibility Timeout — время, пока сообщение скрыто от других consumers во время обработки
Что важно на практике:
• Делайте consumers идемпотентными
• Настраивайте ретраи с exponential backoff
• Следите за длиной очереди и processing lag
• Используйте DLQ для проблемных сообщений
• Не требуйте строгого порядка обработки без реальной необходимости
• Передавайте компактные и самодостаточные сообщения
• Добавляйте Correlation ID для трассировки
Типовые паттерны:
• Work Queue — распределение задач между воркерами
• Pub/Sub — доставка события нескольким подписчикам
• Delayed Queue — отложенная обработка и ретраи
• Priority Queue — приоритетная обработка важных задач
Самая частая ошибка новичков: очередь воспринимают как магическую коробку между двумя сервисами.
На практике очередь лишь переносит сложность из одного места системы в другое.
👉 @BackendPortal
Но очереди сообщений гораздо проще и гораздо опаснее, чем кажется.
Практически за каждой масштабируемой системой стоит очередь.
И за многими крупными инцидентами тоже.
Базовые понятия:
• Queue — очередь сообщений, обычно работающая по принципу FIFO (First In, First Out)
• Producer — отправляет сообщения в очередь
• Consumer — читает и обрабатывает сообщения
• Broker — управляет очередями (Kafka, RabbitMQ, SQS)
• ACK — подтверждение успешной обработки сообщения
• DLQ (Dead Letter Queue) — очередь для сообщений, которые не удалось обработать
• Idempotency — возможность безопасно обработать сообщение повторно без побочных эффектов
• Visibility Timeout — время, пока сообщение скрыто от других consumers во время обработки
Что важно на практике:
• Делайте consumers идемпотентными
• Настраивайте ретраи с exponential backoff
• Следите за длиной очереди и processing lag
• Используйте DLQ для проблемных сообщений
• Не требуйте строгого порядка обработки без реальной необходимости
• Передавайте компактные и самодостаточные сообщения
• Добавляйте Correlation ID для трассировки
Типовые паттерны:
• Work Queue — распределение задач между воркерами
• Pub/Sub — доставка события нескольким подписчикам
• Delayed Queue — отложенная обработка и ретраи
• Priority Queue — приоритетная обработка важных задач
Самая частая ошибка новичков: очередь воспринимают как магическую коробку между двумя сервисами.
На практике очередь лишь переносит сложность из одного места системы в другое.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5
Начал писать Git с нуля на Go как учебный проект.
И это оказался один из тех проектов, которые заставляют по-настоящему понять, как работает инструмент, которым пользуешься каждый день.
Пока реализовал несколько базовых вещей.
Сначала пришлось разобраться с
Потом написал
Неожиданно больше всего времени ушло на нормальную обработку ошибок. Очень быстро начинаешь понимать, почему в Go везде встречается
Дальше перешёл к
До этого я пользовался Git много лет, но никогда не задумывался, что обычный файл внутри превращается в blob, хешируется через SHA-1, сжимается через zlib и сохраняется в объектное хранилище.
Многие знают Git как набор команд.
Гораздо меньше людей знают, что внутри это по сути очень элегантная база данных объектов.
И чем глубже разбираешься в устройстве Git, тем больше начинаешь уважать его архитектуру.
Заодно понял, что писать такие проекты на Go довольно приятно.
👉 @BackendPortal
И это оказался один из тех проектов, которые заставляют по-настоящему понять, как работает инструмент, которым пользуешься каждый день.
Пока реализовал несколько базовых вещей.
Сначала пришлось разобраться с
os.Args и обработкой команд через switch.Потом написал
git init, который создаёт структуру каталогов .git.Неожиданно больше всего времени ушло на нормальную обработку ошибок. Очень быстро начинаешь понимать, почему в Go везде встречается
if err != nil.Дальше перешёл к
hash-object, и тут стало интересно.До этого я пользовался Git много лет, но никогда не задумывался, что обычный файл внутри превращается в blob, хешируется через SHA-1, сжимается через zlib и сохраняется в объектное хранилище.
Многие знают Git как набор команд.
Гораздо меньше людей знают, что внутри это по сути очень элегантная база данных объектов.
И чем глубже разбираешься в устройстве Git, тем больше начинаешь уважать его архитектуру.
Заодно понял, что писать такие проекты на Go довольно приятно.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤1🤔1
Лучший способ понять, как серверы работают на самом деле, — написать пару серверов с нуля.
Автор подготовил серию упражнений, которые помогут вкатиться в socket programming на C, Python и Go:
👉 @BackendPortal
Автор подготовил серию упражнений, которые помогут вкатиться в socket programming на C, Python и Go:
Написать TCP-клиент для telemetry server
https://labs.iximiuz.com/challenges/write-tcp-client-for-telemetry-server
Написать TCP-клиент для chat server
https://labs.iximiuz.com/challenges/write-tcp-client-for-chat-server
Написать TCP echo server с нуля
https://labs.iximiuz.com/challenges/write-tcp-echo-server
Сделать один echo server, который работает и с TCP, и с Unix sockets
https://labs.iximiuz.com/challenges/write-stream-echo-server
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7
Если заглянуть в новый пакет
На первый взгляд это выглядит подозрительно. UUID обычно считаются полностью статeless, так зачем генератору UUID нужен mutex?
Причина связана с UUIDv7.
Команда Go хотела, чтобы функция
Для этого одного timestamp недостаточно. Несколько UUID могут быть созданы в одну и ту же миллисекунду, поэтому генератору приходится помнить состояние предыдущей генерации.
Внутри пакета для этого хранятся пакетные переменные:
Они содержат информацию о последнем сгенерированном UUIDv7.
Поскольку
Алгоритм выглядит примерно так:
Захватить
Проверить текущий timestamp
Сравнить его с предыдущим
При необходимости увеличить внутренний счётчик
Сохранить новое состояние
Сгенерировать UUID
Освободить mutex
В результате каждый новый UUIDv7 гарантированно будет больше предыдущего и корректно отсортируется по времени создания.
Получается интересный компромисс: чтобы обеспечить монотонный порядок UUIDv7, разработчикам пришлось пожертвовать полной статeless-природой генератора и добавить небольшое глобальное состояние, защищённое мьютексом.
👉 @BackendPortal
uuid для Go, можно заметить странную деталь: пакетный mutex v7mu.На первый взгляд это выглядит подозрительно. UUID обычно считаются полностью статeless, так зачем генератору UUID нужен mutex?
Причина связана с UUIDv7.
Команда Go хотела, чтобы функция
NewV7() всегда генерировала UUID, которые сортируются в порядке создания (если системные часы не откатились назад).Для этого одного timestamp недостаточно. Несколько UUID могут быть созданы в одну и ту же миллисекунду, поэтому генератору приходится помнить состояние предыдущей генерации.
Внутри пакета для этого хранятся пакетные переменные:
v7lastSecs
v7lastTimestamp
Они содержат информацию о последнем сгенерированном UUIDv7.
Поскольку
NewV7() может одновременно вызываться из нескольких горутин, доступ к этим данным защищён mutex'ом:var v7mu sync.Mutex
Алгоритм выглядит примерно так:
Захватить
v7muПроверить текущий timestamp
Сравнить его с предыдущим
При необходимости увеличить внутренний счётчик
Сохранить новое состояние
Сгенерировать UUID
Освободить mutex
В результате каждый новый UUIDv7 гарантированно будет больше предыдущего и корректно отсортируется по времени создания.
Получается интересный компромисс: чтобы обеспечить монотонный порядок UUIDv7, разработчикам пришлось пожертвовать полной статeless-природой генератора и добавить небольшое глобальное состояние, защищённое мьютексом.
Please open Telegram to view this post
VIEW IN TELEGRAM
На конференции обсуждали решение прикладных архитектурных задач и разбирали реальные инженерные кейсы. Будет полезно и интересно вне зависимости от стека.
➕ Направленный ациклический граф в PostgreSQL: как мы научили реляционную базу хранить оргструктуру на 500 000 пользователей. Малик Минубаев, разработчик в B2B-платформе, рассказал, почему стандартные паттерны хранения иерархий не работают для ориентированного ациклического графа. А также сравнил несколько вариантов Closure Table с бенчмарками на реальной нагрузке
➕ Как Яндекс Диск выдерживает сотни гигабит входящего трафика: устройство балансировки загрузок. Илья Абрамов, разработчик в Диске, разобрал, почему нам не подошёл подход «как у всех», и показал эволюцию алгоритма балансировки загрузок: от наивного Round-Robin до разработки собственного алгоритма
➕ Как формировать технологический стек и не погибнуть в священных войнах: от хаоса к процессам и техрадару. Дмитрий Сафонов, руководитель команды разработки платформы микросервисов, рассказал, как строить стек для промышленной разработки и разрешать споры о технологиях. А также поделился опытом внедрения Техрадара в Яндекс 360
➕ Зачем и как бэкендеру расти в карьере в 2026 году. Дмитрий Соломонов, руководитель группы B2B-разработки бэкенда Диска, рассказал, как развивать команду с помощью индивидуальных планов и выбора узкой специализации для разных уровней разработчиков. И поделился, как связать получение знаний с реальными задачами
➕ Семь раз подумай, один раз пошардируй: как мы начали горизонтально масштабировать метаданные чатов Телемоста. Никита Звонарев, разработчик в Мессенджере, рассказал, что может предпринять команда, когда вертикально масштабироваться уже не получается, а сервису нужно функционировать дальше в условиях возрастающей нагрузки, и как при этом не устроить себе проблемы в будущем
🎤 Плейлист доступен на YouTube и в VK Видео
Please open Telegram to view this post
VIEW IN TELEGRAM
Один учёный из Дании решил автоматизировать отклики на вакансии через Claude Code. А потом выложил весь проект в open source.
Его зовут Mads Lorentzen. Он PhD-геофизик, а не основатель стартапа. Сделал инструмент для себя и опубликовал его под лицензией MIT.
Как это работает:
Система собирает CV и cover letter в готовые PDF-файлы. Самое интересное не в автоматизации, а в устройстве проекта.
Вся логика хранится в обычных markdown-файлах:
• профиль кандидата
• правила написания текстов
• шаблоны CV
• заметки для подготовки к интервью
• инструкции для агентов
Никакой магии. Всё можно открыть, прочитать и изменить под себя.
Поиск вакансий из коробки заточен под датские job boards, но сам workflow подходит для любой страны.
На момент публикации:
• 489 звёзд
• 270 форков
Такое соотношение форков к звёздам обычно говорит о том, что люди не просто сохраняют репозиторий в закладки, а реально запускают и адаптируют его под себя.
https://github.com/MadsLorentzen/ai-job-search
👉 @BackendPortal
Его зовут Mads Lorentzen. Он PhD-геофизик, а не основатель стартапа. Сделал инструмент для себя и опубликовал его под лицензией MIT.
Как это работает:
Шаг 1
Агент читает вакансию и оценивает, насколько кандидат ей соответствует.
Шаг 2
Создаёт адаптированное CV в LaTeX, оставляя только релевантный опыт.
Шаг 3
Пишет сопроводительное письмо под конкретную позицию.
Шаг 4
Второй AI-агент проводит ревью результата, находит слабые места, после чего первый агент вносит правки.
Шаг 5
Система собирает CV и cover letter в готовые PDF-файлы. Самое интересное не в автоматизации, а в устройстве проекта.
Вся логика хранится в обычных markdown-файлах:
• профиль кандидата
• правила написания текстов
• шаблоны CV
• заметки для подготовки к интервью
• инструкции для агентов
Никакой магии. Всё можно открыть, прочитать и изменить под себя.
Поиск вакансий из коробки заточен под датские job boards, но сам workflow подходит для любой страны.
На момент публикации:
• 489 звёзд
• 270 форков
Такое соотношение форков к звёздам обычно говорит о том, что люди не просто сохраняют репозиторий в закладки, а реально запускают и адаптируют его под себя.
https://github.com/MadsLorentzen/ai-job-search
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4🤔1
Разработчик пишет такой код для обработки 1000 пользовательских записей:
С 10 пользователями в среде разработки всё работает нормально.
Что произойдёт в продакшене с 1000 пользователями?
A) Всё отработает идеально
Promise.all сам управляет конкурентностью
B) Сработает rate limit почтового сервиса
сотни писем тихо не отправятся
C) Серверу не хватит памяти
1000 одновременно запущенных промисов уронят Node.js
D) И B, и C
проблемы с rate limit и памятью
в зависимости от ограничений почтового сервиса
Какой вариант правильный и как это исправить?
Node попытается отправить все 1000 писем одновременно.
В зависимости от инфраструктуры вы получите:
• rate limit от почтового провайдера
• таймауты и ретраи
• резкий рост потребления памяти
• падение производительности процесса
Поэтому правильный ответ обычно не B и не C.
Правильный ответ: D.
Для больших объёмов используют ограничение конкурентности:
👉 @BackendPortal
const users = await db.getAll();
await Promise.all(
users.map(user => sendEmail(user))
);
console.log('Done');
С 10 пользователями в среде разработки всё работает нормально.
Что произойдёт в продакшене с 1000 пользователями?
A) Всё отработает идеально
Promise.all сам управляет конкурентностью
B) Сработает rate limit почтового сервиса
сотни писем тихо не отправятся
C) Серверу не хватит памяти
1000 одновременно запущенных промисов уронят Node.js
D) И B, и C
проблемы с rate limit и памятью
в зависимости от ограничений почтового сервиса
Какой вариант правильный и как это исправить?
Promise.all() не ограничивает конкурентность.Node попытается отправить все 1000 писем одновременно.
В зависимости от инфраструктуры вы получите:
• rate limit от почтового провайдера
• таймауты и ретраи
• резкий рост потребления памяти
• падение производительности процесса
Поэтому правильный ответ обычно не B и не C.
Правильный ответ: D.
Promise.all() не является очередью задач.Для больших объёмов используют ограничение конкурентности:
const limit = pLimit(10);
await Promise.all(
users.map(user =>
limit(() => sendEmail(user))
)
);
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🚀 Курс “Простой ООП до PRO” на Python!
ООП — это не просто очередная тема в программировании. Это база, которую должен понимать каждый разработчик.
Классы, объекты, наследование, инкапсуляция, полиморфизм, композиция и паттерны встречаются почти во всех языках: Python, Java, C++, C#, JavaScript и других.
Что внутри:
• классы и объекты;
•
• наследование, super() и MRO;
• полиморфизм, duck typing и абстрактные классы;
• инкапсуляция, @property, геттеры и сеттеры;
• композиция и агрегация;
• магические методы и перегрузка операторов;
• итераторы, генераторы, модули и пакеты;
• паттерны проектирования;
• финальный проект — RPG-игра.
🎓 12 разделов, 52 урока, практика, поддержка 24/7 и доступ навсегда.
Забрать курс со скидкой 40%:
🔗 https://sudoteach.com/course/oop
ООП — это не просто очередная тема в программировании. Это база, которую должен понимать каждый разработчик.
Классы, объекты, наследование, инкапсуляция, полиморфизм, композиция и паттерны встречаются почти во всех языках: Python, Java, C++, C#, JavaScript и других.
Что внутри:
• классы и объекты;
•
__init__, методы, self, атрибуты;• наследование, super() и MRO;
• полиморфизм, duck typing и абстрактные классы;
• инкапсуляция, @property, геттеры и сеттеры;
• композиция и агрегация;
• магические методы и перегрузка операторов;
• итераторы, генераторы, модули и пакеты;
• паттерны проектирования;
• финальный проект — RPG-игра.
🎓 12 разделов, 52 урока, практика, поддержка 24/7 и доступ навсегда.
Забрать курс со скидкой 40%:
🔗 https://sudoteach.com/course/oop
🔥3💊1
Tail Call Optimization (TCO) — это оптимизация, которая позволяет не создавать новый стековый кадр (stack frame) для вызова функции, если вызывающая функция просто возвращает результат этой функции.
Чаще всего это встречается при хвостовой рекурсии (tail recursion).
Допустим, у вас есть рекурсивная функция:
Представим, что программа начинает работу с первого вызова
Внутри Call 1 происходит ещё один вызов
При любом вызове функции компилятор или интерпретатор создаёт стековый кадр для хранения данных текущего вызова.
Стековый кадр нужен для того, чтобы сохранить состояние Call 1 на случай, если после возврата из Call 2 ему ещё понадобится выполнить какую-то работу.
Но каждый новый стековый кадр занимает память и увеличивает размер стека.
Если все рекурсивные вызовы имеют вид:
то после завершения Call 2 у Call 1 больше нет никакой работы. Он просто сразу возвращает полученный результат.
Получается, что хранить данные Call 1 в отдельном стековом кадре бессмысленно.
Современные компиляторы могут воспользоваться этим. Вместо создания нового стекового кадра они переиспользуют текущий и заменяют данные Call 1 данными Call 2.
В результате новые кадры стека не создаются, а потребление памяти остаётся постоянным:
вместо обычного:
для рекурсии.
Важно понимать, что поддержка Tail Call Optimization не гарантируется большинством языков программирования.
Одним из немногих исключений является язык Scheme, где оптимизация хвостовых вызовов является обязательной частью спецификации языка. Поэтому в Scheme хвостовая рекурсия считается полноценной заменой циклам и может выполняться без риска переполнения стека.
👉 @BackendPortal
Чаще всего это встречается при хвостовой рекурсии (tail recursion).
Допустим, у вас есть рекурсивная функция:
const recur = (args) => {
doSomething(args);
return recur();
}Представим, что программа начинает работу с первого вызова
recur(). Назовём его Call 1.Внутри Call 1 происходит ещё один вызов
recur(). Назовём его Call 2.При любом вызове функции компилятор или интерпретатор создаёт стековый кадр для хранения данных текущего вызова.
Стековый кадр нужен для того, чтобы сохранить состояние Call 1 на случай, если после возврата из Call 2 ему ещё понадобится выполнить какую-то работу.
Но каждый новый стековый кадр занимает память и увеличивает размер стека.
Если все рекурсивные вызовы имеют вид:
return recur();
то после завершения Call 2 у Call 1 больше нет никакой работы. Он просто сразу возвращает полученный результат.
Получается, что хранить данные Call 1 в отдельном стековом кадре бессмысленно.
Современные компиляторы могут воспользоваться этим. Вместо создания нового стекового кадра они переиспользуют текущий и заменяют данные Call 1 данными Call 2.
В результате новые кадры стека не создаются, а потребление памяти остаётся постоянным:
O(1)
вместо обычного:
O(n)
для рекурсии.
Важно понимать, что поддержка Tail Call Optimization не гарантируется большинством языков программирования.
Одним из немногих исключений является язык Scheme, где оптимизация хвостовых вызовов является обязательной частью спецификации языка. Поэтому в Scheme хвостовая рекурсия считается полноценной заменой циклам и может выполняться без риска переполнения стека.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2🔥1
Open NotebookLM — бесплатная open-source альтернатива NotebookLM.
Генерирует подкасты и позволяет общаться со своими документами через чат.
https://github.com/lfnovo/open-notebook
👉 @BackendPortal
Генерирует подкасты и позволяет общаться со своими документами через чат.
https://github.com/lfnovo/open-notebook
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
GitHub - lfnovo/open-notebook: An Open Source implementation of Notebook LM with more flexibility and features
An Open Source implementation of Notebook LM with more flexibility and features - lfnovo/open-notebook
Лето начинается: водные развлечения, гриль на острове и новые маршруты в бутик-отеле «Заонежье»
Для гостей бутик-отеля «Заонежье» к новому сезону подготовлены лесные трассы для первых заездов на новых квадроциклах — они позволяют исследовать дикие уголки карельской тайги и скалистые берега озер. Велопрогулки по дорогам Заонежья стали еще комфортнее благодаря электробайкам, которые этой весной пополнили велопарк отеля.
В мае, в отеле открылся сезон водных развлечений: гостям доступны сапы, каяки и весельные лодки. В этом году пользование ими - комплементарное для всех гостей. Также появились новые маршруты для катеров по заливам Онежского озера.
Ресторан «Руна» представляет летнюю серию гриль-сетов, которые можно приготовить самостоятельно на одном из необитаемых островов или устроить барбекю на лужайке у дома. В меню — овощные и рыбные сеты, а также мясное ассорти.
Бутик-отель «Заонежье» приглашает к активному отдыху среди озер и северной природы Карелии.
Для гостей бутик-отеля «Заонежье» к новому сезону подготовлены лесные трассы для первых заездов на новых квадроциклах — они позволяют исследовать дикие уголки карельской тайги и скалистые берега озер. Велопрогулки по дорогам Заонежья стали еще комфортнее благодаря электробайкам, которые этой весной пополнили велопарк отеля.
В мае, в отеле открылся сезон водных развлечений: гостям доступны сапы, каяки и весельные лодки. В этом году пользование ими - комплементарное для всех гостей. Также появились новые маршруты для катеров по заливам Онежского озера.
Ресторан «Руна» представляет летнюю серию гриль-сетов, которые можно приготовить самостоятельно на одном из необитаемых островов или устроить барбекю на лужайке у дома. В меню — овощные и рыбные сеты, а также мясное ассорти.
Бутик-отель «Заонежье» приглашает к активному отдыху среди озер и северной природы Карелии.
🔥1💊1