
Обратная совместимость Python-пакета: цена импорта в цифрах
Пакет с ленивыми импортами ради совместимости грузился 380 мс на старте. Разбираем, где утекает время при поддержке старого API и как вернуть 40 мс без слома пользовательского кода.

Пакет с ленивыми импортами ради совместимости грузился 380 мс на старте. Разбираем, где утекает время при поддержке старого API и как вернуть 40 мс без слома пользовательского кода.

Схему меняете миграциями, а перелив данных гоните руками в проде на глазах у пользователей. Разбираем, чем платит каждый из подходов к миграции данных и когда какой выбрать.

async with молча пропускает освобождение ресурсов при отмене задачи, ломает порядок выхода при вложенности и не работает в синхронном коде. Разбираем, где именно это происходит и что мерить.

Библиотека вышла с версией 2.4.1, CI собрался зелёным, а через час прод начал падать с TypeError. Разбираем, где обратная совместимость дала трещину и как этого избежать.

Переименовали параметр — и у сотни проектов упал импорт. Разбираем, какие изменения в публичном API ломают чужой код и на что смотреть в ревью, прежде чем нажать merge.

Один необязательный ключ, который приходил строкой вместо числа, ронял отчёт раз в неделю. Разбираем, где протекает валидация в Python-сервисе и чем pydantic отличается от ручных проверок под нагрузкой.

asyncio.gather молча продолжает работу, когда одна из задач падает, а её соседи повисают в фоне. TaskGroup из Python 3.11 закрывает эту дыру структурной отменой и группировкой ошибок.

Внешне библиотека работает, но каждое обновление ломает чужой код. Разбираем, где граница между публичным и приватным на самом деле проходит и почему её нарушают первой.

Задача не отменяется мгновенно, а «сгоревшая» корутина ловит CancelledError и молча продолжает работать. Разбираем, что происходит внутри asyncio при отмене и таймауте и где утекают ресурсы.

Разбираем, как отделить публичный интерфейс библиотеки от внутренностей: __all__, ведущее подчёркивание, __init__.py и обещания, которые потом придётся держать в каждом релизе.

time.time() врёт при переводе часов, а timeit запускает код тысячи раз не просто так. Разбираем, каким инструментом мерить что и почему разброс замеров — не шум, а информация.

Как asyncio выполняет тысячи корутин на одном потоке: что делает event loop за один оборот, при чём тут epoll и почему await не блокирует остальные задачи.