За пределами совместимости API: создание инструмента для оценки масштаба последствий изменений в библиотеках
- Netflix создала Quasar: инструмент индексирует определения API и ссылки на них в репозиториях-потребителях с помощью SCIP.
- При проверке пул-реквеста Quasar сравнивает базовый и целевой коммиты, выявляет изменения API и оценивает ссылки потребителей.
- В иллюстративном отчёте удалённый метод используется в 137 проиндексированных репозиториях; указано распределение по версиям 4.2.1, 4.1.7 и 3.9.4.
Почему это важно: Данные помогают разработчикам оценить масштаб воздействия изменения и выбрать дальнейшие действия до выпуска.
[не удалось получить полный текст]
Автор: Роберто Перес Альколеа, команда Java Platform
Quasar связывает предлагаемое изменение API с обнаруженными ссылками в репозиториях-потребителях, предоставляя разработчику библиотеки данные для принятия решения о выпуске
В Netflix общие библиотеки Java поддерживают приложения, разрабатываемые в экосистеме множества репозиториев, которые развиваются независимо друг от друга. Изменение библиотеки начинается в одном репозитории, но затронуть оно может многие другие. Разработчики библиотеки видят перед собой разницу в API. Но часто они не знают, кто всё ещё зависит от изменённых символов.
Потребность в такой информации растёт по мере того, как агенты программирования берут на себя всё больше этапов жизненного цикла разработки ПО. Агент может ускорить локальное редактирование, но без контекста других репозиториев он не способен оценить риски для потребителей или помочь спланировать их переход на новую версию. Данные, на которые разработчик библиотеки опирается при оценке изменения, могут помочь и работающему над ним агенту.
Рассмотрим распространённый случай: удаление устаревшего API. Устаревшие точки входа увеличивают объём того, что разработчикам библиотеки нужно тестировать, документировать и поддерживать, а также могут ограничивать развитие библиотеки.
Предположим, что замена доступна уже несколько выпусков, а старый метод не позволяет задавать параметры, необходимые для новой функциональности. Тесты библиотеки проходят, а средство проверки совместимости предупреждает об удалении. Но разработчик библиотеки всё ещё не может ответить на вопросы, от которых зависит дальнейший план действий:
- Вызывает ли кто-нибудь из потребителей этот метод?
- Сосредоточены ли потребители на одной версии или распределены между несколькими поколениями?
- Реализует ли или оборачивает ли API другая библиотека, увеличивая тем самым масштаб воздействия?
- Достаточно ли напрямую связаться с командами или необходимы кампания по объявлению API устаревшим и переходу на новую версию?
В небольшом масштабе разработчики библиотеки могут обратиться к соседним командам или поискать нужное в нескольких репозиториях. Но когда репозиториев много, найти все вызовы метода и выяснить, какую версию библиотеки использует каждый, сложнее. Эти сведения разбросаны по кодовым базам и сборкам потребителей.
Без таких данных разработчик библиотеки может выпустить несовместимое изменение и узнать о его последствиях лишь после сбоев у потребителей — или бесконечно сохранять старый API из-за неопределённости рисков. Библиотеки должны развиваться, и их разработчикам нужны данные, позволяющие делать это осознанно.
Мы создали Quasar для индексации определений символов и ссылок на них во всех репозиториях Netflix. Разработчикам библиотек этот общий индекс помогает ответить на два вопроса:
- Что изменилось в публичном API библиотеки?
- В каких репозиториях используются именно те символы, которые изменились?
Первый вопрос помогает выявить потенциально несовместимое изменение. Второй — оценить его фактический масштаб воздействия. Вместе они превращают общее предупреждение о совместимости в данные, на основании которых разработчик библиотеки может действовать до слияния изменений или выпуска релиза.
От изменений API к последствиям для потребителей
Существующие методы позволяют увидеть лишь разные стороны проблемы. Инструменты проверки бинарной и исходной совместимости выявляют изменения контракта, но не показывают, кто использует изменённый API. Графы зависимостей отражают объявленные связи, но не доказывают, что код вызывает конкретный метод. Текстовый поиск может пропустить перегруженные методы, наследование или версию артефакта, к которому относится вызов. Сборки потребителей дают надёжную проверку, но запускать их во всём парке репозиториев дорого.
Quasar построен на основе SCIP — открытого формата обмена данными для семантического анализа кода. Индексаторы для конкретных языков кодируют определения, ссылки и связи, используя стабильные идентификаторы символов. Quasar сохраняет определения API для версий и коммитов библиотек наряду со ссылками из репозиториев-потребителей. Благодаря общим идентификаторам он может связать изменение API в одном репозитории с точными местами использования в других, даже если эти репозитории индексировались независимо.

При каждой сборке CI в подключённом репозитории индексаторы для конкретных языков отправляют индексы SCIP в службу приёма данных Quasar. Она сохраняет определения API и ссылки потребителей в формате Parquet в Amazon S3, сохраняя идентификатор символа, версию зависимости и расположение в исходном коде, необходимые для анализа изменения.
Во время проверки пул-реквеста Quasar сравнивает индексированные определения базового и целевого коммитов, а также подсчитывает прямые ссылки потребителей с помощью Amazon Athena. Quasar предоставляет результаты через API REST и GraphQL и MCP-сервер; последующие запросы об использовании позволяют получить разбивку по версиям зависимостей и расположение в исходном коде. Отдельная оценка влияния на совместимость может также проследить реализации и их вызовы, если разработчик библиотеки укажет изменённый символ JVM.
Рассмотрим упрощённый пример изменения API:
public interface Client {
- Result getLegacyValue(Request request);
+ Result getValue(Request request, Options options);
}
Для подробной оценки влияния удаления на совместимость инструмент на стороне разработчика библиотеки передаёт дескриптор старого метода. Quasar формирует его канонический идентификатор символа. В этом сокращённом фрагменте запроса Quasar к Amazon Athena показано, как устроено сопоставление прямых ссылок:
SELECT c.change_id, 'DIRECT_REFERENCE' AS evidence_kind,
r.scm_type, r.org, r.repo, r.dep_version, r.file_path
FROM requested_changes c
JOIN quasar.symbol_refs r
ON r.symbol_canonical = c.target_canonical
requested_changes содержит изменения API, переданные разработчиком библиотеки. Фрагмент SQL-запроса находит репозитории, в которых вызывается удалённый метод. Quasar также проверяет реализации и вызовы через них, чтобы каждый затронутый репозиторий учитывался только один раз. Для дальнейшего анализа он возвращает примеры версий зависимостей и расположений файлов.
В случае изменения Client это показывает разработчику библиотеки, в каких репозиториях всё ещё используется getLegacyValue, какие версии там применяются и где находятся некоторые из этих вызовов. Это помогает решить, нужно ли согласовать переход на новую версию до удаления метода.
Анализ до выпуска
Сравнение версий полезно при планировании обновления или подготовке руководства по миграции. Ещё больше пользы разработчики библиотек получают, когда обратная связь приходит во время проверки кода.
Для анализа пул-реквестов Quasar хранит снимки определений API, привязанные к коммитам. Получив базовый и целевой коммиты, система классифицирует символы как добавленные, удалённые или изменённые по сигнатуре. Удаления и изменения затем рассматриваются как кандидаты для анализа влияния на потребителей.
Несовместимое изменение не обязательно сопряжено с высоким риском. Quasar показывает фактический масштаб воздействия, чтобы разработчик библиотеки мог решить, как поступить; система не навязывает политику выпуска. «Ссылок не обнаружено» означает лишь, что Quasar не нашёл их среди проиндексированных данных. Рефлексия, конфигурация, динамическая загрузка, устаревшие ветки или неполная индексация могут скрывать потребителей. В результатах должно быть указано, проиндексированы ли запрошенные коммиты, насколько свежи индексы потребителей и не были ли данные усечены.
Для проверки пул-реквеста нужны проиндексированные снимки именно базового и целевого коммитов. Если хотя бы один из них недоступен, Quasar сообщает, что сравнить их не удалось, и не подставляет снимок ветки по умолчанию. Благодаря этому отсутствие сравнения не выглядит как отсутствие изменений в API.
Вернёмся к изменению Client. Этот иллюстративный отчёт объединяет данные, доступные через сравнение API в Quasar, запросы об использовании потребителями и оценку критичности библиотеки. Это не буквальный ответ какого-либо одного API:
{
"change": "REMOVED",
"symbol": "Client#getLegacyValue(Request)",
"affectedRepositories": 137,
"versionDistribution": [
{ "version": "4.2.1", "repositories": 86 },
{ "version": "4.1.7", "repositories": 38 },
{ "version": "3.9.4", "repositories": 13 }
],
"sampleConsumerLocations": [
{
"repository": "checkout-service",
"filePath": "src/main/java/com/example/checkout/CheckoutClient.java",
"lines": [84, 129]
},
{
"repository": "client-wrapper",
"filePath": "src/main/java/com/example/client/ClientAdapter.java",
"lines": [57]
}
],
"libraryCriticality": {
"tier": 1,
"basis": "highest-tier downstream application"
},
"comparison": {
"baseShaFound": true,
"headShaFound": true
}
}
Отчёт о влиянии показывает 137 затронутых репозиториев, использующих версии библиотеки 4.2.1, 4.1.7 и 3.9.4.
Количество репозиториев относится к конкретному символу: в этом примере удалённый метод используется в 137 проиндексированных репозиториях. Распределение по версиям показывает, что основная группа использует версию 4.2.1, а небольшая группа всё ещё работает с 3.9.4. Разработчик библиотеки может просмотреть затронутые репозитории и получить индексированные пути к файлам, а также номера строк, если индекс содержит эти данные. Чтобы пример было проще читать, в JSON приведены только два примера расположений. Структура filePath и lines соответствует контракту запросов Quasar. Уровень критичности даёт более широкий контекст о библиотеке и определяется уровнем самого критичного приложения, зависящего от неё; это не значит, что все 137 потребителей относятся к Tier 1.
Вместе эти данные меняют план разработчика библиотеки. Вместо того чтобы удалить метод и ждать сбоев, он может сохранить старый метод, объявить его устаревшим, опубликовать путь миграции, согласовать переход в более широком масштабе и отслеживать оставшиеся версии, прежде чем удалить метод. Пути к файлам и доступные номера строк превращают оценку масштаба в конкретный список задач для инженеров или агентов программирования. Если к той же разнице в API прилагаются слабые или устаревшие данные, решение будет иным: сначала следует обновить индексы. Ценность заключается не только в обнаружении удаления, но и в выборе соразмерного следующего шага.
Рабочий процесс до выпуска дополняет сведения об изменениях API данными о влиянии на потребителей и качестве доказательств, прежде чем разработчик библиотеки решит, как действовать дальше
Многоязычная основа на базе SCIP
Общий формат SCIP позволяет Quasar индексировать и несколько языковых экосистем. Индексатор каждого языка анализирует соответствующий код, а Quasar использует полученные идентификаторы символов для поиска ссылок в разных репозиториях.
Например, client-lib индексирует Client#getLegacyValue (Request) как определение, а checkout-service — как ссылку на тот же символ. Затем Quasar может связать API библиотеки с его использованием в другом репозитории.
Индексаторы для конкретных языков передают определения, ссылки и связи SCIP в общий семантический граф Quasar.
Связи особенно полезны, когда сгенерированный код отделяет принадлежащий разработчику библиотеки API от символов, которые вызывают потребители. Например, Quasar может проследить путь от определения Protobuf через созданные для него элементы Java до репозиториев, в которых они используются, даже если код потребителя напрямую не ссылается на элемент .proto.
SCIP фиксирует символы и ссылки на них, но не определяет, нарушает ли изменение API правила совместимости конкретной экосистемы. Сейчас Quasar сравнивает определения API JVM и Protobuf в индексированных данных и прослеживает изменения Protobuf через сгенерированный код Java, чтобы находить затронутые репозитории. В отдельном процессе оценки влияния на совместимость JVM инструмент на стороне разработчика библиотеки определяет нарушения, по которым Quasar ищет затронутые репозитории. Go, Python, JavaScript/TypeScript и Rust поддерживаются в запросах об использовании, но Quasar пока не оценивает несовместимые изменения API для этих языков.
Более ранняя оценка рисков
Сейчас Quasar показывает результаты анализа изменений API в пул-реквестах, включая число обнаруженных потребителей и степень уверенности. С помощью других запросов можно изучить версии зависимостей и расположение в исходном коде, используя критичность библиотеки как более широкий контекст. Вместе эти данные помогают принять решение до слияния изменений.
Мы хотим получать этот контекст ещё раньше. Агент, который пишет код библиотеки, должен распознавать изменения публичных символов и обращаться к Quasar до того, как они попадут в пул-реквест. API Quasar и интеграция с Model Context Protocol (MCP) обеспечивают доступ к данным, но одного доступа недостаточно, чтобы агент понимал, когда ими воспользоваться. Рабочий процесс разработки также должен распознавать изменения публичного API, чтобы агент знал, когда запрашивать оценку влияния и когда привлекать разработчика библиотеки.
Сегодня Quasar оценивает риски в пул-реквесте. В будущем агенты будут получать контекст о влиянии на потребителей ещё во время написания кода, до открытия пул-реквеста.
Рекомендации на раннем этапе не заменят анализ пул-реквеста. Проверка PR по-прежнему будет подтверждать конкретную разницу в коде и выявлять изменения, которые не были распознаны во время написания кода. Охват, актуальность, неоднозначность, неподдерживаемые платформы и усечение данных должны передаваться в машиночитаемом виде на обоих этапах. Агент не должен интерпретировать «в доступном индексе не обнаружено использований» как «можно безопасно удалить».
Сейчас агенты могут обращаться к Quasar через MCP по запросу. Мы работаем над тем, чтобы этот контекст стал частью процесса разработки, а затем планируем использовать найденные места вызовов для подготовки изменений, необходимых для миграции. Quasar предоставляет семантические данные, агент сокращает рутинную работу по миграции, а ответственность за решения об API и выпусках остаётся за разработчиком библиотеки.
Выводы
Создание этого процесса помогло нам сформулировать четыре практических вывода.
- Разделяйте совместимость и охват. Удаление метода может нарушить контракт API, даже если Quasar не обнаружил его вызовов. Список затронутых репозиториев и используемых в них версий библиотеки показывает предстоящий объём работ по миграции. Чтобы выбрать путь выпуска, разработчикам библиотеки нужны оба показателя.
- Делайте данные проверяемыми. Число репозиториев полезнее, если к нему прилагаются примеры мест вызова и разбивка по версиям. В результатах также нужно указывать, какие коммиты были проиндексированы, насколько свежи индексы потребителей и не были ли данные усечены. Иначе «использований не найдено» можно ошибочно принять за доказательство того, что изменение никого не затронет.
- Разделяйте анализ использования и совместимости для разных языков. Благодаря SCIP Quasar может находить ссылки на символы в нескольких экосистемах. Чтобы определить, нарушает ли изменение API совместимость, нужны правила конкретной экосистемы или надёжный сигнал от инструмента на стороне разработчика библиотеки.
- Предоставляйте данные разработчику библиотеки, пока выбор ещё не сделан. Результаты проверки пул-реквеста могут побудить разработчика сохранить API, опубликовать путь миграции или согласовать действия потребителей до слияния изменений. Если перенести те же данные в процесс разработки, они смогут повлиять на редактирование ещё раньше. После выпуска данные всё равно помогут найти потребителей, которым нужно перейти на новую версию.
Сейчас Quasar индексирует код на JVM, Go, Python, JavaScript/TypeScript и Rust для анализа использования в разных репозиториях. Он сравнивает API JVM и отслеживает изменения Protobuf через сгенерированный код Java. Разработчики библиотек могут просматривать результаты анализа изменений через API REST и GraphQL Quasar или его MCP-сервер, а затем изучать затронутые репозитории и места вызовов. Мы развиваем эту основу: добавляем проверки совместимости для конкретных экосистем, более глубокую интеграцию с проверкой кода и помощь агентов при миграции потребителей, сохраняя за разработчиком библиотеки право утверждать выпуск.
Quasar используется внутри Netflix, но этот подход можно применять и в других компаниях: семантически индексировать код, хранить определения API, сравнивать их в момент внесения изменений, находить затронутых потребителей и сообщать о качестве данных. Разработчикам библиотек недостаточно вердикта о совместимости. Им нужно знать, кого может затронуть изменение, и иметь достаточно времени, чтобы принять меры до выпуска.
Огромное спасибо команде Java Platform в Netflix. Их опыт, сотрудничество и поддержка сделали эту работу возможной
Связанные доклады
- От задержек к молниеносным обновлениям: как сократить сроки обновления зависимостей рассказывает о том, как Netflix сократила сроки обновления зависимостей.
- Путь Netflix к уверенным автоматизированным изменениям кода посвящён тому, как повысить надёжность автоматизированных изменений в крупном масштабе.
Статья «За пределами совместимости API: создание инструмента для оценки масштаба воздействия изменений библиотек» впервые была опубликована в Netflix TechBlog на Medium, где читатели продолжают обсуждение, отмечая ключевые моменты и комментируя эту историю.
