AI
Habr AI
Ни зарплат, ни отпусков, ни больничных. Зато есть User Story и Merge Request: как AI‑агенты работают у меня в Jira
Открыть оригинал ↗ Перевод заголовка: Ни зарплат, ни отпусков, ни больничных. Зато есть User Story и Merge Request: как AI-агенты работают у меня в Jira
В компании IT-команда использует Jira как основной трекер, где теперь в поле Assignee назначаются не люди, а AI-агенты — фронтенд-разработчики, бэкенд-разработчики и аналитики. Агенты выполняют ограниченные задачи (oneshot), такие как добавление кнопки или подготовка требований, не заменяя людей в ревью и принятии решений. Работа идёт через серверный harness, который интегрирован с Jira, Confluence и GitLab, обеспечивая автоматическое создание MR, проверки кода и документации. Важно, что агенты не могут изменять код напрямую, если это не предусмотрено, и в сложных случаях (например, при постановке бизнес-требований) задают вопросы, которые затем решаются человеком.
- Агенты получают задачи через поле Assignee в Jira, как обычные коллеги, и выполняют их в изолированном окружении с доступом к проектной документации и репозиториям.
- Для каждого агента настроены роли, модели, инструкции и доступы, что позволяет единообразно применять правила по всем задачам.
- Результаты включают MR, документацию и логи, но ревью остаётся за человеком — агенты не заменяют команду, а лишь ускоряют выполнение определённых этапов.
- Система поддерживает автозапуск, возврат к заданию и отслеживание расхода токенов, но не хранит внутренние рассуждения модели.
- Важно, что агенты не могут работать с репозиториями в режиме редактирования — их результаты (например, User Story) требуют ручного подтверждения и публикации.
Когда пригодится
Материал полезен для команд, которые уже используют Jira и хотят внедрить AI-агентов для автоматизации небольших, повторяющихся задач — например, добавление элементов интерфейса, подготовка требований или формирование User Story. Особенно актуален в средних компаниях, где есть структура и инструкции, но не хватает времени на ручную подготовку задач.
Вопросы для размышления
- Если агенты начинают генерировать 30 MR в день вместо одного, как изменится стратегия ревью — будет ли оно распределено между разработчиками, усилено автоматическими проверками, или задачи будут пересмотрены с более жёсткими критериями приёмки?
- Если агенты уже выполняют задачи, которые раньше делали джун-разработчики, как это повлияет на обучение команды — кто будет отвечать за ревью AI-кода и как это может быть интегрировано в систему развития кадров?
Java / Spring
HowToDoInJava
TypeScript 7 Native Go Compiler: tsc, tsgo and Migration
Открыть оригинал ↗ Перевод заголовка: TypeScript 7: нативный компилятор на Go, tsc, tsgo и миграция
TypeScript 7 представляет собой стабильную версию, в которой компилятор и сервис языка перенесены с JavaScript на Go. Команда tsc теперь работает как нативный бинарный файл, что позволяет сократить время компиляции в 4–12 раз по сравнению с версией 6, особенно на больших проектах. Важно понимать, что переход возможен только в тех случаях, когда в сборке используется только tsc, а не инструменты, которые импортируют TypeScript как библиотеку. В таких случаях компилятор остаётся на версии 6, так как в TypeScript 7 отсутствует программируемый API (например, createProgram). При миграции необходимо убрать устаревшие настройки в tsconfig.json (например, target: es5, moduleResolution: node10, baseUrl), и проверить, что выходные файлы (.js, .d.ts) идентичны в обоих версиях.
- Миграция возможна только при отсутствии инструментов, импортирующих TypeScript как библиотеку (например,
ts-loader,typescript-eslint). - Устаревшие настройки в
tsconfig.json(например,baseUrl,target: es5) должны быть удалены до перехода. - Время компиляции в TypeScript 7 на 4–12 раз быстрее, но эффективность зависит от архитектуры системы и количества ядер.
- Команда
tsgoустарела и больше не рекомендуется — она была только предварительной версией, прекратившейся 7 июля 2026 года. - Программируемый API (например,
createProgram) отсутствует в версии 7 и появится в 7.1, что ограничивает использование в инструментах, зависящих от него.
Когда пригодится
Материал полезен для команд, которые используют
tscв CI и имеют небольшой или средний размер проекта, где время компиляции критично. Особенно актуален для монорепозиториев с длинными CI-процессами и для проектов, где выходные файлы должны быть идентичны между версиями.
Вопросы для размышления
- Какой компромисс между производительностью и стабильностью возникает при использовании
tscв среде с несколькими инструментами, зависящими от старого API, если они не могут обновиться до версии 7.1?- В каких условиях (по размеру проекта, количеству ядер, настройкам
tsconfig.json) скорость компиляции в TypeScript 7 может достигать 10x, и как это влияет на выбор времени миграции?- Какие риски связаны с тем, чтобы в проекте одновременно использовать
typescript@7.0.2и@typescript/typescript6, если в нём есть инструменты, требующие старый API?
MCP Tool Poisoning: A Local Demo and Defenses in Python
Открыть оригинал ↗ Перевод заголовка: Угроза заражения инструментов MCP: локальный демо и защита на Python
Атака MCP tool poisoning заключается в том, что сервер скрывает инструкции в метаданных инструмента, и модель интерпретирует их как команды от пользователя. Поскольку описание инструмента передаётся в контекст модели как обычный текст, разработчик, составляющий описание, может непосредственно влиять на поведение модели. Пользователь видит лишь имя инструмента в диалоге, а не полный текст, что делает угрозу незаметной. Важно, что при установке серверов из реестров или репозиториев или при разработке собственных серверов, разработчики должны внедрять защиту.
Четыре практические меры эффективны: хеширование описаний инструментов (pinning), отображение полного описания перед одобрением, сканирование текста на наличие инструкций и запуск серверов с минимальными правами доступа. Хеширование — наиболее простое и автоматизированное решение: при первом одобрении вычисляется SHA-256 от всей структуры инструмента, а при последующих проверках — сравнивается с хешем. Сканер идентифицирует скрытые теги, приказы и упоминания иностранных инструментов. Проверка на наличие инструкций в описании и результатах вызова инструмента позволяет обнаружить атаки на разных этапах.
Когда пригодится
Материал полезен при разработке или внедрении AI-агентов, использующих внешние инструменты, особенно в средах, где используются сторонние серверы или интегрируются с внешними API. Критически важен при работе с открытыми или публичными репозиториями инструментов, где описание может быть изменено после одобрения. Особенно актуален для команд, которые не контролируют весь цикл развертывания инструментов.
Вопросы для размышления
- Какова сложность реализации хеширования инструментов в условиях динамического обновления описаний, если серверы могут обновляться без предварительного уведомления и без контроля версий?
- В каких случаях сканер поиска инструкций может пропустить атаку, если атакующий использует синонимичные формулировки или переформулированные инструкции, не включающие явные теги?
- Какова надёжность защиты при использовании агентов с низкой пропускной способностью, если каждый вызов инструмента требует проверки результата, но при этом серверы запускаются в одном процессе без изоляции?
Free-Threaded Python (No-GIL): Writing Thread-Safe Code
Открыть оригинал ↗ Перевод заголовка: Свободная потоковая Python (без GIL): написание потокобезопасного кода
В Python 3.14 появился опциональный режим выполнения без Global Interpreter Lock (GIL), позволяющий нескольким потокам одновременно использовать несколько ядер процессора при выполнении CPU-нагруженных задач. В отличие от стандартной версии, где GIL блокирует выполнение кода только для одного потока за раз, в режиме без GIL потоки могут работать параллельно, что значительно улучшает производительность при обработке вычислительных задач. Однако это не делает операции, такие как counter += 1, атомичными — они всё ещё подвержены конкуренции, и для предотвращения потерь данных требуется использование блокировок или очередей. Ключевые инструменты для потокобезопасности включают threading.Lock, threading.RLock, queue.Queue и ThreadPoolExecutor, каждый из которых подходит в зависимости от модели взаимодействия между потоками.
- Режим без GIL — это отдельная сборка CPython (например,
python3.14t), а не включение в стандартную версию. - Без GIL потоки могут работать параллельно на нескольких ядрах, что даёт значительное ускорение для CPU-нагруженных задач.
- Операции, включающие чтение и запись в общие переменные (например,
counter += 1), остаются неатомичными и требуют блокировок даже в режиме без GIL. - Потокобезопасность достигается через блокировки, очереди или использование
ThreadPoolExecutor, который избегает прямого доступа к общим данным. - Важно проверять состояние GIL во время запуска (через
sys._is_gil_enabled()), так как он может быть включён вручную через переменную среды или опцию-X gil.
Когда пригодится
Материал полезен при разработке CPU-нагруженных приложений (например, обработка изображений, математические вычисления), где параллельная работа потоков даст реальное ускорение. Особенно актуален он при наличии сложных структур данных, которые обновляются несколькими потоками, и при необходимости избежать потерь данных из-за неатомичных операций.
Вопросы для размышления
- Какой компромисс между производительностью и стабильностью возникает при использовании
threading.Lockв цикле с большим числом итераций, и как это влияет на масштабируемость при увеличении количества потоков?- При каких условиях
ThreadPoolExecutorможет быть предпочтительнее, чемqueue.Queue, и как это влияет на выбор архитектуры при работе с большими объёмами данных?- Какова вероятность возникновения race condition в коде, который прошёл тесты на стандартной версии Python, при переходе на free-threaded build, и как это может быть оценено без реальных нагрузок?
Python JIT Compiler: Enable, Benchmark and When to Use
Открыть оригинал ↗ Перевод заголовка: Python JIT-компилятор: включение, бенчмаркинг и когда его использовать
Новый JIT-компилятор в CPython (с 3.13) работает на уровне машинного кода, транслируя «горячие» блоки байт-кода в машинные инструкции во время выполнения. Он использует метод copy-and-patch и впервые включён в официальную версию Python, но остаётся экспериментальным и не рекомендуется для использования в production. Официальные бенчмарки показывают средний прирост скорости от 4 до 12%, но это среднее значение по разным программам и платформам — реальные результаты на обычных машинах, особенно в виртуальных средах, могут быть неуловимыми или даже отрицательными.
- Скорость улучшения минимальна для большинства реальных приложений — JIT не ускоряет код, который не содержит типоустойчивых числовых циклов.
- Для точного измерения нужно запускать тест несколько раз и смотреть на медиану, а не на среднее значение, чтобы избежать шума от фоновых процессов.
- JIT работает только на определённых типах кода — чистые арифметические циклы без вызовов функций и создания объектов.
- Он не ускоряет код, работающий в Numpy, pandas или других библиотеках, где медленные участки уже находятся в C-коде.
- В production использовать JIT нельзя — он нестабилен, может быть удалён без предупреждения, и инструменты профилирования не работают корректно.
Когда пригодится
Материал полезен, если вы разрабатываете специализированный численный цикл (например, в физике или математике), где вы хотите проверить, насколько JIT может ускорить конкретный кусок кода. Он не подходит для обычных веб-приложений или скриптов, где скорость не критична.
Вопросы для размышления
- Почему виртуальная машина с двумя ядрами не даёт стабильного результата, и как это влияет на доверие к измерениям JIT-ускорения?
- Какой из компиляторов (PyPy, Numba, Cython) лучше подходит для ускорения численных вычислений в реальном приложении, и в каких случаях JIT CPython может быть альтернативой?
- Если JIT не ускоряет код, который вызывает функции или создаёт объекты, как это влияет на выбор между использованием CPython и PyPy для проектов с большими циклами?
Python Lazy Imports: The lazy Keyword and Alternatives
Открыть оригинал ↗
Перевод заголовка: Python: ленивые импорты, ключевое слово lazy и альтернативы
Ленивые импорты в Python откладывают загрузку модуля до первого его использования, в отличие от обычных (жадных) импортов, которые загружают модуль сразу при выполнении инструкции import. В Python 3.15, начиная с релиза 9 октября 2026 года, реализовано ключевое слово lazy в рамках PEP 810, которое позволяет откладывать загрузку модулей до первого обращения к имени. При этом lazy import json сразу привязывает имя к прокси-объекту, а сам модуль загружается только при первом вызове, например, json.dumps(). Такой подход особенно полезен в командах-инструментах, где не все подкоманды используют все зависимости — например, команда list может не требовать модулей для работы с XML или архивами.
Практические тезисы:
— Ленивые импорты сокращают время запуска программы, если в конкретном запуске не используются определённые модули.
— Ключевое слово lazy работает только на уровне модуля (вне функций, классов и блоков try), и не поддерживается внутри функций или блоков.
— При первом использовании имени, прокси-объект разрешается и модуль загружается, а ошибка при несуществующем модуле выдаётся на этом этапе.
— Для старых версий Python (до 3.15) можно использовать импорты внутри функций или importlib.util.LazyLoader, хотя это требует дополнительной настройки.
— Важно учитывать, что ленивые импорты могут вызывать побочные эффекты (например, регистрацию модулей при первом обращении), и такие случаи требуют явного управления.
Когда пригодится
Материал полезен в тех случаях, когда запуск приложения должен быть максимально быстрым, а в конкретной сессии используются только часть модулей — например, в CLI-инструментах, где подкоманды имеют разные зависимости. Особенно эффективно при наличии большого количества импортов, которые не используются в большинстве случаев.
Вопросы для размышления
- Какой компромисс между производительностью и надёжностью возникает при использовании ленивых импортов в приложении, где отсутствие модуля может привести к критической ошибке на уровне выполнения?
- В каких условиях ленивый импорт может привести к непредсказуемому поведению в многопоточной среде, и как это может быть обходится при архитектуре, где модули регистрируются при первом обращении?
- При каких условиях использование
lazyв сочетании с__getattr__илиLazyLoaderстановится предпочтительнее, чем встроенныйlazyв Python 3.15, с точки зрения масштабируемости и поддержки на разных версиях Python?
Context Bloat in AI Agents: Causes, Cost and How to Fix It
Открыть оригинал ↗ Перевод заголовка: Бloat контекста в ИИ-агентах: причины, стоимость и способы устранения
Контекст-блоат — это рост объёма токенов в запросе модели, который не нужен для текущего шага, например, из-за вставки полных файлов или ненужных результатов инструментов. Важно это в код-агентах и других приложениях, где каждый шаг агента повторяет весь контекст, включая инструкции, описания инструментов и историю диалога. Такой рост увеличивает стоимость запроса, замедляет ответ и может снижать точность ответа. В примере из статьи файлы и результаты инструментов составляют 95,9% от общего объёма запроса, что делает их главной целью для оптимизации.
- Удаление избыточных данных — сокращение результатов инструментов, например, ограничение количества строк или сохранение только неудачных тестов.
- Замена вставки полных файлов на извлечение кусков (chunks) по запросу, что снижает объём вручную добавляемого контента.
- Компактное хранение истории диалога — замена старых сообщений на один обобщённый фрагмент.
- Загрузка инструментов по запросу (on-demand), вместо включения всех описаний в начало запроса.
- Использование подагента с собственным контекстом для выполнения отдельных задач.
- Кэширование стабильного префикса (системных инструкций), что уменьшает повторяющийся объём запроса.
Когда пригодится
Материал полезен при разработке ИИ-агентов, работающих с большими объёмами кода или историей диалога, где важно минимизировать стоимость запросов и сохранить точность ответов.
Вопросы для размышления
- Какой компромисс между сокращением контекста и потерей важной детали может возникнуть при использовании trim-инструментов для результатов тестов, если модель должна идентифицировать конкретную строку в логе?
- В каких условиях (по масштабу, нагрузке, типу задачи) может быть оправдано использование подагента вместо кэширования префикса, если оба подхода снижают объём контекста, но вводят разные риски?
- Как изменится сложность и надёжность агента при переходе от вставки полных файлов к извлечению кусков, если в процессе извлечения возникают ошибки в сопоставлении по TF-IDF?
Python UTF-8 Default Encoding: What Changes in Python 3.15
Открыть оригинал ↗ Перевод заголовка: Проверка по умолчанию UTF-8 в Python: что изменилось в Python 3.15
В Python 3.15 по умолчанию для функции open() без явного указания кодировки теперь используется UTF-8 на всех платформах, в отличие от предыдущих версий, где на Windows по умолчанию применялась кодировка системы (например, cp1252). Это изменение введено в рамках PEP 686 и затрагивает не только чтение файлов, но и другие интерфейсы, такие как pathlib и subprocess, которые теперь также используют UTF-8 по умолчанию. Без явного указания кодировки в open() Python 3.15 корректно расшифровывает UTF-8-файлы, а при попытке открыть файл в старой кодировке (например, cp1252) с акцентами — вызывает ошибку UnicodeDecodeError. Для надёжности и совместимости в любом коде следует всегда явно указывать кодировку при работе с файлами.
- Всегда передавайте явную кодировку (например, "utf-8") в вызове open(), чтобы избежать зависимости от системы и версии Python.
- При работе с файлами, созданными в старой кодировке (cp1252), используйте encoding="cp1252" для корректного чтения.
- Для файлов, которые должны соответствовать системной кодировке (например, ввод старых приложений), используйте encoding="locale".
- Важно понимать, что UTF-8-файлы, ранее читавшиеся как "малопонятные" в cp1252, теперь работают правильно, а cp1252-файлы требуют явного указания кодировки.
- Проверяйте код на совместимость с разными версиями Python и платформами, используя тесты с отключённым UTF-8-режимом (PYTHONUTF8=0).
Когда пригодится
Материал полезен при миграции существующего кода с Windows-кодировок (cp1252) на UTF-8, особенно в средах, где используются старые приложения или файлы, созданные в системной кодировке. Также полезен при разработке приложений, работающих на разных ОС и требующих стабильности поведения при чтении и записи текстовых файлов.
Вопросы для размышления
- В каких случаях использование encoding="locale" может привести к непредсказуемому поведению в production-среде, особенно при работе с разными системными настройками?
- Какой компромисс между совместимостью с старыми файлами и безопасностью при использовании UTF-8 по умолчанию в Python 3.15, если файлы были созданы в cp1252 и не переписывались?
- При каких условиях может возникнуть failure mode при использовании subprocess.run() с text=True на системах с cp1252-кодировкой, и как это можно предотвратить без изменения кода?
Stateless MCP: How the 2026-07-28 Spec Removes Sessions
Открыть оригинал ↗ Перевод заголовка: Stateless MCP: как спецификация 2026-07-28 удаляет сессии
Новая версия протокола MCP с даты 2026-07-28 полностью устраняет сессии: теперь каждый запрос содержит всю необходимую информацию, и сервер не должен хранить состояние между запросами. Вместо того чтобы инициализироваться и передавать сессионный идентификатор, клиент теперь отправляет все метаданные в заголовках и теле запроса, что позволяет любому экземпляру сервера обрабатывать запрос без предыдущего состояния. Вместо хранения данных в памяти одного экземпляра сервера, данные перемещаются в "хэндлы", возвращаемые инструментами, и хранятся в общем хранилище, доступном всем экземплярам.
- Каждый запрос включает в себя версию протокола, информацию о клиенте и его возможностях в метаданных, что устраняет необходимость в инициализации и сессионных идентификаторах.
- Сессионные идентификаторы и потоковые соединения удаляются: серверы больше не сохраняют открытые соединения или сессии, и при сбое потока клиент пересылает запрос с новым идентификатором.
- Вместо хранения состояния в памяти одного экземпляра, данные (например, плейлисты) теперь сохраняются в общем хранилище, доступном всем инстансам, что обеспечивает масштабируемость и отказоустойчивость.
- Вместо прямого вмешательства в поток, серверы возвращают "хэндлы", которые клиент передаёт в последующие вызовы, позволяя избежать зависимости от конкретного экземпляра.
- В случае запросов, требующих ввода от пользователя, используется механизм
input_required, при котором сервер возвращает состояние и запрос повторяется с новым идентификатором, что делает систему устойчивой к сбоям и перезапускам.
Когда пригодится
Материал полезен при разработке распределённых AI-сервисов, где требуется высокая масштабируемость и отказоустойчивость, особенно при использовании нескольких экземпляров сервера за прокси. Он особенно актуален для систем, где сессии и состояние между запросами являются источником проблем при масштабировании, и где важна возможность перезапуска без потери данных.
Вопросы для размышления
- Какой минимальный вклад в сложность алгоритма должен быть введён для обеспечения безопасности при повторном вызове инструмента с использованием requestState, если не предусмотрено проверка подписи на стороне клиента?
- В каких сценариях может привести к нестабильности отказ от поддержки потоковых соединений и резумации при сбое, особенно при работе с инструментами, требующими ввода от пользователя в процессе выполнения?
- Какие риски связаны с использованием общего хранилища данных при высокой нагрузке, если не предусмотрена синхронизация и контроль доступа между экземплярами сервера?
Upgrade Python Version: A Safe Migration Guide
Открыть оригинал ↗ Перевод заголовка: Обновление версии Python: руководство по безопасной миграции
Обновление версии Python — это переход кода с одной версии на более новую, без изменений в самой логике, но с изменением интерпретатора. При этом некоторые модули или функции могут быть удалены или изменены, и именно на этом этапе нужно выявлять и исправлять проблемы. Руководство предлагает пошаговый процесс, включающий проверку изменений в релизах, тестирование на старой версии с включёнными ошибками на предупреждениях, исправление найденных проблем и последующую проверку на новой версии.
- Проверяйте релиз-заметки перед миграцией, чтобы понять, какие модули удаляются или меняются в новой версии.
- Устанавливайте новую версию Python рядом с текущей, чтобы избежать потери обратной совместимости.
- Используйте виртуальные окружения для изоляции каждой версии Python и тестирования кода в отдельных средах.
- Включайте предупреждения как ошибки на старой версии, чтобы выявить все вызовы, которые будут прерваны в новой версии.
- После исправления — запускайте тесты на новой версии, чтобы убедиться, что миграция не повлияла на функциональность.
Когда пригодится
Материал полезен при планировании обновления Python в проектах, где требуется безопасная и стабильная миграция без риска сбоя в работе, особенно при наличии зависимостей, которые не поддерживают новые версии.
Вопросы для размышления
- Какой компромисс между скоростью миграции и полнотой обнаружения проблем возникает, если использовать только тесты на старой версии с включёнными предупреждениями, не проверяя поведение на новой версии до исправлений?
- В каких сценариях может привести к сбоям использование виртуальных окружений, если они не настроены правильно или не обновляются при изменении Python-версии?
- Какой риск остаётся, если зависимость не предоставляет wheel-пакета для новой версии Python, и как это влияет на выбор версии для миграции?
SKILL.md Guide: Write a Good Skill for Coding Agents
Открыть оригинал ↗ Перевод заголовка: Руководство по написанию хорошей навыка для агентов кода
Навык — это папка с инструкциями для повторяющегося действия, который загружается только тогда, когда возникает соответствующая задача. Ключевой файл — SKILL.md — содержит YAML-метаданные с именем и описанием, а в теле — пошаговые инструкции. Описание критически важно: оно определяет, будет ли агент загружать навык вообще. Хороший навык включает в себя чёткое описание его функции, сценариев использования и случаев, когда его не применять. Основные принципы: структурированные шаги вместо текста, конкретные методы выполнения, короткие и точные описания, разделение деталей на ссылки, которые загружаются только при необходимости.
- Описание должно быть ясным и включать три компонента: что делает навык, когда его использовать и когда не использовать.
- В теле навыка используются пронумерованные шаги, а не объяснительный текст, чтобы агент последовательно выполнял действия.
- Каждый шаг должен быть конкретным — либо гибким (с пространством для выбора), либо жёстким (с обязательным выполнением), чтобы избежать ошибок.
- Важно разделять детали, которые нужны только в определённых случаях, на отдельные файлы в папке references/, которые загружаются по условию.
- Навык должен быть коротким (менее 500 строк и 5000 токенов), и включать в себя проверки на корректность вывода и работы с внешними скриптами при необходимости.
Когда пригодится
Материал полезен при разработке систем, где есть повторяющиеся задачи по коду (например, генерация изменений в релизе, проверка коммитов), и когда важно минимизировать контекст, который агент хранит, чтобы избежать перегрузки и улучшить скорость реакции.
Вопросы для размышления
- Какой компромисс между точностью и гибкостью в шагах навыка возникает, если в задаче есть несколько допустимых решений, но агент должен выбрать одно из них?
- При каких условиях использование скрипта в навыке может привести к снижению надёжности, если агент не может выполнить его в условиях, отличных от тестовых?
- Как изменится поведение навыка при масштабировании — например, если в репозитории будет 100 навыков, и каждый из них требует отдельных ресурсов для загрузки?
System Design
DEV System Design
System Design Interview Framework: Navigating the 45-Minute Architecture Round
Открыть оригинал ↗ Перевод заголовка: Фреймворк системного проектирования: навигация по 45-минутному архитектурному раунду
В системном проектировании ключевое значение имеет переход от интуитивных решений к структурированным подходам, которые позволяют избежать рисков, связанных с масштабированием и отказами. Основные проблемы — нестабильная задержка, скрытые сбои и высокая вычислительная нагрузка — возникают при неправильной архитектурной организации, особенно при росте нагрузки. Для надежного функционирования требуется четкая последовательность: от определения требований до анализа узких мест и внедрения защитных механизмов.
- Важно строго ограничивать параллельную обработку (через семафоры) и избегать накопления заданий в памяти, чтобы предотвратить перегрузку и OOM-ошибки.
- Все внешние вызовы должны сопровождаться жесткими таймаутами, чтобы избежать зависаний и блокировки рабочих потоков.
- Все операции, изменяющие состояние, должны быть идемпотентными, чтобы гарантировать корректность при повторных попытках выполнения.
- Архитектура должна включать в себя наблюдаемость через метрики (например, латентность, ошибки), чтобы быстро выявлять сбои.
- Нужно проектировать отказоустойчивость с механизмами быстрого отказа и падения, а не просто ждать восстановления.
Когда пригодится
Материал особенно полезен при подготовке к техническим интервью, где требуется демонстрация понимания архитектурных принципов, а также при разработке реальных систем, где важны отказоустойчивость, масштабируемость и наблюдаемость.
Вопросы для размышления
- Как изменится поведение системы при увеличении количества задач, если не использовать лимиты на параллельную обработку, и что это может привести к ошибкам в production?
- В каких сценариях идемпотентность может быть нарушена, и как это влияет на надежность системы при повторных попытках выполнения операций?
- Какой минимальный набор метрик должен быть включен в систему для эффективного обнаружения узких мест и сбоев, и как эти метрики могут быть интегрированы в реальную инфраструктуру без перегрузки?
Monolith versus distributed system
Открыть оригинал ↗ Перевод заголовка: Монолит против распределённой системы
При подготовке к вакансии в компании с распределёнными системами обмена сообщениями и событийной архитектурой я понял, что чем больше компонентов в системе, тем выше вероятность её нестабильности. Монолиты обеспечивают лучшую согласованность, низкую задержку и высокую доступность, что соответствует принципам CAP-теоремы. При правильной реализации монолиты могут превосходить распределённые системы по производительности и надёжности, но они уступают им в вопросах безопасности, поскольку не поддерживают принцип минимальных привилегий. В распределённых системах можно реализовать более гибкую и безопасную архитектуру, особенно в критически важных сценариях.
- Монолиты обеспечивают стабильность и низкую задержку благодаря простоте и однородности логики.
- Они лучше справляются с согласованностью и доступностью, что критично для высокопроизводительных приложений.
- В условиях безопасности монолиты уступают, так как не позволяют эффективно применять принцип минимальных привилегий.
- Распределённые системы, несмотря на сложность, предпочтительны в критически важных и защищённых средах.
- Выбор между архитектурами зависит от баланса между производительностью, надёжностью и безопасностью.
Когда пригодится
Материал полезен при проектировании систем, где важны производительность и согласованность, например, в корпоративных приложениях с низкой задержкой и стабильностью, но не подходит для решений, где безопасность и изоляция компонентов являются приоритетом.
Вопросы для размышления
- Какой компромисс между производительностью и безопасностью может быть достигнут в гибридной архитектуре, сочетающей монолит и распределённые сервисы?
- В каких условиях распределённая система может быть менее надёжной, чем монолит, несмотря на наличие событийной архитектуры?
- Как влияет масштабирование на безопасность в распределённых системах, и какие failure modes могут возникнуть при неоптимальной настройке привилегий?
Designing an Email Service at Scale
Открыть оригинал ↗ Перевод заголовка: Проектирование сервиса электронной почты на масштабе
Чтобы построить распределённую платформу, способную обрабатывать 1 миллиард пользователей, 50 миллиардов сообщений в день и петабайты данных без потерь, необходимо разделять архитектуру на два независимых потока: отправку и получение. Каждый поток использует специализированные компоненты — от REST-интерфейсов и хранения в S3 до очередей на Kafka и проверок в DNS — чтобы обеспечить надёжность, безопасность и масштабируемость. Ключевые технические вызовы включают юридическую обязательность ответа SMTP 250 OK, риск потери данных из-за неудачной записи в базу, угрозу блокировки IP-адреса при отправке балансов на фальшивые адреса и необходимость оптимизации модели хранения для поддержания низкой задержки.
- Как обеспечить, чтобы ответ SMTP 250 OK не приводил к утрате данных, если он должен подтверждать доставку, но при этом требует репликации в нескольких зонах?
- В каких условиях использование атомарной операции в Cassandra может привести к неожиданному поведению при масштабировании или отказах?
- Какие альтернативы модели шардинга по user_id и временным квадратам могут снизить риски роста задержек при увеличении числа пользователей?
Когда пригодится
Материал полезен при проектировании масштабируемых сервисов, где критичны надёжность доставки, безопасность и юридические обязательства, особенно в системах с высокой нагрузкой и большим объёмом данных.
Вопросы для размышления
- Вопрос?
- Вопрос?
- Вопрос?
Operational Durability: Building and Operating Resilient Production Systems
Открыть оригинал ↗ Перевод заголовка: Операционная устойчивость: создание и эксплуатация устойчивых производственных систем
Устойчивость систем означает не просто сохранение работоспособности в нормальных условиях, а способность к предсказуемому восстановлению после сбоев и интеграцию этих сбоев в долгосрочное проектирование. В высокорисковых средах, таких как финтех и авиация, сбои не являются исключениями — они являются детерминированными реальностями, и система должна быть спроектирована так, чтобы гладко деградировать, самовосстанавливаться и предоставлять прозрачную информацию в кризисных ситуациях.
- Устранение единичных точек отказа: каждый слой системы должен иметь явный режим деградации, чтобы поддерживать критическую функциональность даже при сбоях.
- Определение RTO и RPO как ключевых метрик: время восстановления и допустимая потеря данных напрямую влияют на архитектуру хранения и вычислений.
- Использование GitOps и Policy-as-Code для обеспечения воспроизводимости и автоматической проверки конфигураций, что снижает риски человеческих ошибок.
- Внедрение стратегий развертывания (blue-green или canary) для минимизации рисков при обновлениях и быстрого возврата к предыдущей версии.
- Работа с контейнерами требует строгого контроля ресурсов, пробы и бюджетов, чтобы избежать сбоев из-за перегрузки или нестабильности.
Когда пригодится
Материал особенно полезен для команд, разрабатывающих критически важные системы в финансах, медицине или транспорте, где сбои могут привести к серьёзным последствиям и где требуется высокая надёжность, быстрое восстановление и прозрачность в кризисах.
Вопросы для размышления
- Какой компромисс между затратами на репликацию и RTO может быть допустим в среде с ограниченным бюджетом, где RPO не может быть ниже 1 часа?
- В каких условиях PDB может привести к нежелательному поведению в кластере, если не учитывать динамику нагрузки и типы сервисов?
- Какие риски связаны с использованием короткого TTL в кэшировании секретов, если секреты обновляются реже, чем TTL, и при этом система не обновляет конфигурацию в реальном времени?
Decide where the error lands
Открыть оригинал ↗ Перевод заголовка: Определите, где ошибка оказывается
В распределённых системах ошибки не должны просто ловиться и скрываться — они должны быть направлены на конкретные компоненты, которые способны их обработать. Простое вложение try/catch не решает проблему: ошибка может оказаться у пользователя, не дать никакого уведомления и привести к неправильному поведению, как в случае с покупкой, где клиент получил сообщение об успешной оплате, но ничего не получили. Ключевая ошибка — в том, что система не задумывается, где именно ошибка должна "попасть", а просто ловит её и отбрасывает в лог. Правильный подход — проектировать систему так, чтобы каждый возможный сбой оказался в блоке, способном его обработать: в очереди (для задержки и повтора), в рабочем процессе (с автоматическим повтором и идемпотентностью) или в обмене с внешним сервисом. Если ошибка попадает на пользователя — это критическая ошибка, и она должна быть исключена. АИ-ассистенты часто предлагают "робастные" обработчики, которые просто ловят ошибки и возвращают 200, не задавая вопроса, кто и когда узнает о сбое.
Когда пригодится
Материал полезен при проектировании систем, где важно не просто ловить ошибки, а управлять их потоком — например, в сервисах с высокой нагрузкой, где критичны отказоустойчивость и прозрачность реакции на сбои.
Вопросы для размышления
- Как изменится поведение системы, если в очереди добавить ограничение на размер пакета, и как это повлияет на идемпотентность повторных вызовов?
- При каких условиях идемпотентность рабочего процесса может привести к непредсказуемым результатам, и как это может быть обнаружено в production?
- Если внешний сервис возвращает "not done" вместо "fine", как это влияет на сроки повторных попыток и как это может быть оценено в условиях реального использования?
Reversibility and Recovery in Healthcare Agentic AI
Открыть оригинал ↗ Перевод заголовка: Восстановимость и восстановление в агентных ИИ для здравоохранения
В здравоохранении безопасность ИИ оценивается не только по точности моделей, но и по способности системы безопасно реагировать на сбои. Агентные системы требуют четкой структуры состояний — от предложения до выполнения и сбоев — с контролем переходов и защитами на каждом этапе. При этом для операций, которые теоретически могут быть отменены, предусмотрены механизмы отмены, компенсации или возврата к предыдущему состоянию, особенно важно для многошаговых процессов, где могут возникнуть несоответствия или частичные успехи. Логи должны фиксировать не только действия, но и их авторизацию и временные метки, чтобы избежать уничтожения истории изменений. Некоторые действия, особенно с высоким риском, не могут быть отменены, и тогда требуется строгая предварительная проверка, явное одобрение и возможность поднятия на уровень управления. Умная агентная система должна быть способна остановиться, если неясно, как продолжать, а не пытаться исправить ошибку, продолжая выполнение.
Когда пригодится
Материал полезен при проектировании систем, где безопасность и прозрачность изменений критичны — например, в автоматизированных процессах диагностики, назначения лекарств или ведения медицинских записей.
Вопросы для размышления
- Какие риски могут возникнуть при попытке отменить действие в медицинской системе, если оно уже было записано в истории пациента?
- В каких условиях отмена действия может быть не только технически, но и этически неприемлема, даже если технически возможно?
- Как можно оценить сложность и масштабируемость архитектуры, обеспечивающей восстановление, при наличии зависимостей между шагами в клиническом потоке?
I Added a Fourth Shard in Python and 75% of the Keys Moved
Открыть оригинал ↗ Перевод заголовка: Я добавил четвёртую шард и 75% ключей переместилось
При простом шардинге — хеширование ключа и деление на количество шардов — добавление нового шарда приводит к масштабному перемещению данных. При переходе от 3 к 4 шардам 75% ключей перемещаются, а при росте от 10 к 11 шардам — до 91%, что противоречит упрощённому утверждению о 9% перераспределении. Основная причина — ключ остаётся на том же шарде только тогда, когда остатки хеша по старому и новому количеству шардов совпадают, что случается редко (в среднем 1 из 11). В отличие от этого, в системе с кольцом (ring) перемещение данных значительно меньше — около 25%, при условии равномерного распределения виртуальных узлов. При неравномерном распределении (один виртуальный узел на реальный) доля перемещённых ключей может варьироваться от 0,8% до 71,4%, что показывает высокую чувствительность к начальным условиям. Виртуальные узлы решают проблему неравномерного распределения нагрузки, делая распределение более предсказуемым и стабильным.
Когда пригодится
Материал полезен при проектировании распределённых систем, где важно понимать, как изменение количества шардов влияет на перемещение данных, особенно при выборе между модульным шардингом и кольцевой моделью. Особенно актуален для разработчиков, работающих с кэшами, CDN или системами хранения, где требуется минимизировать перераспределение при масштабировании.
Вопросы для размышления
- Почему при переходе от 10 к 11 шардам перемещается почти 91% ключей, а не около 9%, и как это связано с вероятностью совпадения остатков хеша?
- Как влияет количество виртуальных узлов на дисперсию нагрузки в кольцевой модели, и при каких условиях доля перемещённых ключей может достигать 70%?
- В чём заключается фундаментальный компромисс между простотой реализации модульного шардинга и стабильностью распределения при добавлении новых узлов?
InfoQ Architecture
Amazon Acquires DuckLabs and Integrates DuckDB in Amazon Aurora PostgreSQL
Открыть оригинал ↗ Перевод заголовка: Амазон приобрела DuckLabs и интегрировала DuckDB в Amazon Aurora PostgreSQL
Amazon приобрела компанию DuckLabs, разработчика аналитической БД DuckDB, и внедрила её в сервис Amazon Aurora PostgreSQL. Участники проекта, включая создателей DuckDB, продолжат руководить разработкой и техническим направлением открытого исходного кода, оставаясь в рамках неприбыльной DuckDB Foundation. Интеграция позволяет в одном запросе объединять актуальные транзакционные данные из Aurora с историческими данными из Amazon S3, Apache Iceberg и Parquet, без необходимости в ETL-пайплайнах и дополнительных сетевых переходов. Это упрощает архитектуру, снижает затраты и минимизирует риски синхронизации данных.
- DuckDB остаётся бесплатным и открытым исходным кодом под лицензией MIT, что поддерживает экосистему и привлекает разработчиков.
- Интеграция в Aurora PostgreSQL позволяет выполнять сложные аналитические запросы прямо в базе, не требуя промежуточных этапов обработки.
- Работа с данными в S3, Iceberg и Parquet происходит в рамках Aurora, что уменьшает задержки и снижает нагрузку на инфраструктуру.
- Услуга доступна в всех коммерческих регионах AWS и AWS GovCloud без дополнительной платы — стоимость зависит только от вычислительных ресурсов и запросов к S3.
- Внедрение ориентировано на AI-работы, где часто требуется быстрая экспертиза данных перед принятием решений.
Когда пригодится
Материал полезен для разработчиков и архитекторов, работающих над системами аналитики, где требуется быстрая интеграция операционных и исторических данных без сложных ETL-процессов, особенно в контексте AI-агентов и динамических аналитических запросов.
Вопросы для размышления
- Какова вероятность того, что подобная интеграция может быть применена к системам с высокой нагрузкой на транзакции, если DuckDB не оптимизирован для больших объёмов данных?
- В каких сценариях может возникнуть конфликт между производительностью DuckDB и требованиями к безопасности данных в AWS, особенно при работе с чувствительными данными в S3?
- Какие ограничения могут быть у DuckDB в контексте поддержки сложных JOIN-операций между большими таблицами в Iceberg и Aurora, если не используется расширенная архитектура?
React Java
20 System Design Courses That Actually Prepare You for Interviews
Открыть оригинал ↗ Перевод заголовка: 20 курсов по системному проектированию, которые действительно готовят к собеседованиям
Системное проектирование — одна из самых сложных тем в технических интервью, и многие кандидаты не справляются с вопросами по масштабируемости, балансировке нагрузки, отказоустойчивости и другим ключевым аспектам. В статье представлены 20 проверенных курсов от ведущих платформ, разработанных экспертами, имеющими опыт как в проведении, так и в подготовке к собеседованиям. Курсы охватывают как базовые принципы (например, масштабирование, кэширование, выбор баз данных), так и продвинутые темы (распределённые системы, шардинг, отказоустойчивость). Особое внимание уделено практическим задачам, интерактивным упражнениям и реальным сценариям, таким как разработка сервиса по сокращению URL или парковки. Многие из курсов включают мок-интервью с обратной связью, что позволяет лучше подготовиться к реальным условиям.
Когда пригодится
Материал особенно полезен для кандидатов, стремящихся пройти собеседования в FAANG-компаниях, и для тех, кто хочет не просто выучить ответы, а понять фундаментальные принципы проектирования систем. Особенно ценен для тех, кто уже имеет базу в программировании, но не имеет опыта работы с распределёнными системами или масштабируемыми архитектурами.
Вопросы для размышления
- В каких случаях использование NoSQL баз данных может быть более эффективным, чем SQL, и как это влияет на выбор архитектуры при проектировании системы?
- Какой компромисс между масштабируемостью и отказоустойчивостью может быть наиболее рациональным в условиях ограниченного бюджета ресурсов и времени?
- В каких сценариях шардинг базы данных может привести к ухудшению производительности, и как это может быть обнаружено на практике?
Coding / Algorithms
LeetCode.ca Solutions
4041 - Minimum Operations to Form Subset Sum II
Открыть оригинал ↗ Перевод заголовка: 4041 - Минимальное количество операций для формирования подмножественной суммы II
В задаче требуется найти минимальное количество операций (умножение на 2 или деление на 2 с округлением вниз), чтобы в массиве после операций существовало подмножество, сумма которого равна заданному значению. Каждая операция может быть выполнена в любом порядке, но любая последовательность умножения, за которой следует деление, не меняет значение элемента — это пустая операция. Следовательно, любая последовательность операций эквивалентна сначала делению на 2^i, затем умножению на 2^j, что приводит к значению ⌊x/2^i⌋×2^j за i+j операций. Задача сводится к 0-1-пакету: для каждого элемента мы рассматриваем все возможные пары (i,j), и ищем минимальное количество операций для достижения суммы sum. Если такой путь невозможен, возвращаем -1.
- Каждый элемент может быть преобразован в значение ⌊x/2^i⌋×2^j за i+j операций, где i — количество делений, j — количество умножений.
- Внутри пакета для каждого элемента перебираются все возможные значения i и j, и для каждого из них вычисляется минимальная стоимость достижения суммы.
- Используется динамическое программирование с массивом f[w], где f[w] — минимальное количество операций для подмножества, сумма которого равна w.
- При неразрешимости (f[sum] остается бесконечным) возвращается -1.
Когда пригодится
Материал полезен при решении задач по динамическому программированию, где требуется оптимизировать последовательность преобразований элементов для достижения целевой суммы, особенно когда операции могут быть комбинированы и сокращены.
Вопросы для размышления
- Как изменится ответ, если в задаче разрешено использовать более чем один элемент для формирования одного значения через операции, и при этом сумма должна быть достигнута с помощью подмножества, а не всей последовательности?
- При каких условиях может быть достигнута минимальная стоимость, если исходный массив содержит только чётные числа, и как это повлияет на количество делений и умножений?
- Какова сложность алгоритма при увеличении суммы sum до 10000, и как это влияет на память и время выполнения при фиксированном размере массива?