Темы



За пределами совместимости API: создание инструмента для оценки масштаба последствий изменений библиотеки

Коротко сгенерировано ИИ по тексту статьи
  • Netflix создала Quasar, индексирующую определения API и ссылки на символы в репозиториях-потребителях.
  • При проверке pull request Quasar сравнивает базовый и конечный коммиты и ищет затронутые репозитории, версии зависимостей и места вызовов.
  • В иллюстративном отчёте удаление метода затрагивает 137 репозиториев; большинство использует библиотеку версии 4.2.1.

Почему это важно: Данные о влиянии до выпуска помогают разработчику выбрать план перехода, прежде чем удалять API.

[не удалось получить полный текст]

Автор: Roberto Perez Alcolea, команда Java Platform

Quasar связывает предлагаемое изменение API с обнаруженными ссылками в репозиториях-потребителях, предоставляя разработчику библиотеки данные для принятия решения о выпуске

В Netflix общие библиотеки Java используются приложениями, разрабатываемыми в масштабной экосистеме репозиториев, которые развиваются независимо друг от друга. Изменение библиотеки начинается в одном репозитории, но его последствия могут затронуть многие другие. Разработчики библиотеки видят разницу в API. Но часто им неизвестно, кто всё ещё зависит от изменённых символов.

Необходимость в такой видимости растёт по мере того, как агенты для написания кода берут на себя всё большую часть жизненного цикла разработки ПО. Агент может ускорить локальное изменение, но без контекста из других репозиториев он не способен оценить риски для downstream-потребителей или помочь спланировать их переход на новую версию. Данные, которыми разработчик библиотеки пользуется для оценки изменения, могут также помочь работающему над ним агенту.

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

Предположим, что замена доступна уже несколько выпусков, а старый метод не позволяет передавать параметры, необходимые для новой функциональности. Тесты библиотеки проходят, а средство проверки совместимости предупреждает об удалении. Но разработчик библиотеки всё ещё не может ответить на вопросы, от которых зависит дальнейший план действий:

  • Продолжает ли кто-нибудь из потребителей вызывать этот метод?
  • Используют ли потребители преимущественно одну версию или они распределены между несколькими поколениями?
  • Реализует или оборачивает ли API другая библиотека, увеличивая тем самым масштаб последствий?
  • Достаточно ли прямой координации или нужна кампания по объявлению API устаревшим и переходу на новую версию?

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

Без этих данных разработчик библиотеки может выпустить несовместимое изменение и узнать о его последствиях из-за сбоев у потребителей либо бесконечно сохранять старый API, поскольку риски неизвестны. Библиотеки должны развиваться, и их разработчикам нужны данные, которые помогут делать это осознанно.

Мы создали Quasar, чтобы индексировать определения символов и ссылки на них в репозиториях Netflix. Разработчикам библиотек этот общий индекс помогает ответить на два вопроса:

  1. Что изменилось в публичном API библиотеки?
  2. В каких репозиториях используются именно изменённые символы?

Первый вопрос помогает обнаружить потенциально несовместимое изменение. Ответ на второй позволяет оценить фактический масштаб его воздействия. Вместе они превращают общее предупреждение о совместимости в данные, на основе которых разработчик библиотеки может действовать до слияния изменений или выпуска версии.

От изменений API к их влиянию на потребителей

Существующие методы позволяют увидеть лишь отдельные стороны проблемы. Инструменты проверки бинарной и исходной совместимости выявляют изменения контракта, но не показывают, кто использует изменённый API. Графы зависимостей отражают объявленные связи, но не подтверждают, что код вызывает конкретный метод. Текстовый поиск может пропустить перегруженные методы, наследование или версию артефакта, к которой относится вызов. Сборки потребителей дают надёжную проверку, но запускать их по всей экосистеме дорого.

В основе Quasar лежит SCIP — открытый формат обмена данными для семантического анализа кода. Специализированные для каждого языка индексаторы кодируют определения, ссылки и связи с помощью стабильных идентификаторов символов. Quasar хранит определения API для версий и коммитов библиотек наряду со ссылками из репозиториев-потребителей. Общая идентичность позволяет связать изменение API в одном репозитории с точными местами его использования в других, даже если эти репозитории индексировались независимо.

При каждой подключённой сборке CI индексаторы для соответствующих языков отправляют индексы SCIP в службу приёма данных Quasar. Она записывает определения API и ссылки из репозиториев-потребителей в формате Parquet в Amazon S3, сохраняя идентификаторы символов, версии зависимостей и расположение в исходном коде, необходимые для анализа изменения.

При проверке pull request 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, какие версии там применяются и где находятся некоторые из этих вызовов. Это помогает решить, нужно ли согласовать переход на новую версию до удаления метода.

Анализ до выпуска

Сравнение версий полезно при планировании обновления или подготовке руководства по переходу на новую версию. Но разработчики библиотек получают ещё больше пользы, когда обратная связь поступает во время проверки кода.

Для анализа pull request Quasar хранит снимки определений API, привязанные к коммитам. Получив базовый и конечный коммиты, система классифицирует символы как добавленные, удалённые или изменённые по сигнатуре. Удалённые и изменённые символы затем становятся кандидатами для анализа влияния на потребителей.

Несовместимое изменение не обязательно сопряжено с высоким риском. Quasar сообщает о наблюдаемом влиянии, чтобы разработчик библиотеки мог решить, что делать; система не навязывает правила выпуска. Формулировка «ссылок не обнаружено» означает лишь, что Quasar не нашла их среди проиндексированных данных. От потребителей могут скрыть отражение, конфигурация, динамическая загрузка, устаревшие ветки или неполная индексация. В результатах нужно указывать, были ли проиндексированы запрошенные коммиты, насколько актуальны индексы потребителей и не были ли данные усечены.

Для проверки pull request нужны индексированные снимки именно базового и конечного коммитов. Если хотя бы один из них недоступен, 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 библиотеки с его использованием в другом репозитории.

Специализированные для каждого языка индексаторы передают в общий семантический граф Quasar определения, ссылки и связи SCIP.

Связи особенно полезны, когда сгенерированный код разделяет API, которым владеет разработчик библиотеки, и символы, вызываемые потребителями. Например, Quasar может проследить путь от определения Protobuf через сгенерированные элементы Java до репозиториев, где они используются, даже если в коде потребителей нет прямого обращения к элементу .proto.

SCIP фиксирует символы и ссылки на них, но не определяет, нарушает ли изменение API правила совместимости конкретной экосистемы. На сегодняшний день Quasar сравнивает определения API JVM и Protobuf в индексированных данных, а также прослеживает изменения Protobuf через сгенерированный код Java, чтобы находить затронутые репозитории. Отдельный сценарий оценки влияния на совместимость JVM использует информацию о нарушениях, выявленных инструментом на стороне разработчика библиотеки, для поиска затронутых репозиториев. Quasar поддерживает запросы об использовании для Go, Python, JavaScript/TypeScript и Rust, но пока не оценивает несовместимые изменения их API.

Более ранняя оценка рисков

Сейчас Quasar показывает результаты анализа изменений API в pull request, в том числе число выявленных потребителей и степень уверенности. С помощью других запросов разработчики библиотек могут изучить версии зависимостей и расположение в исходном коде, используя критичность библиотеки как дополнительный контекст. Вместе эти данные помогают принять решение до слияния изменений.

Мы хотим предоставлять этот контекст раньше. Агент, пишущий код библиотеки, должен распознавать изменения публичных символов и обращаться к Quasar, прежде чем они превратятся в pull request. API Quasar и интеграция с Model Context Protocol (MCP) обеспечивают доступ к данным, но одного доступа недостаточно: система сама не станет учитывать этот контекст. Рабочий процесс разработки должен также распознавать изменения публичного API, чтобы агент знал, когда нужно запросить оценку влияния и привлечь разработчика библиотеки.

Сегодня Quasar оценивает риски в pull request. В будущем агенты будут получать контекст о влиянии на потребителей прямо во время написания кода, до открытия pull request.

Рекомендации на раннем этапе не заменят анализ pull request. Проверка PR по-прежнему будет сверять фактическую разницу и выявлять изменения, которые не были распознаны во время написания кода. Данные о полноте охвата, актуальности, неоднозначности, неподдерживаемых платформах и усечении результатов должны передаваться в обе проверки в машиночитаемом виде. Агент не должен превращать фразу «в доступном индексе не обнаружено использований» в вывод «можно безопасно удалить».

Сегодня агенты могут обращаться к Quasar через MCP, если их об этом попросить. Мы работаем над тем, чтобы этот контекст стал частью рабочего процесса разработки, а затем планируем использовать обнаруженные места вызова для подготовки изменений, необходимых для миграции. Quasar предоставляет семантические данные, агент сокращает рутинную работу по миграции, а разработчик библиотеки по-прежнему отвечает за решения, связанные с API и выпуском.

Наши выводы

Работа над этим процессом привела нас к четырём практическим выводам.

  • Разделяйте совместимость и масштаб использования. Удаление метода может нарушить контракт API, даже если Quasar не обнаружит вызывающих его мест. Список затронутых репозиториев и используемых в них версий библиотеки показывает объём предстоящей миграции. Чтобы выбрать стратегию выпуска, разработчикам нужны оба показателя.
  • Обеспечьте возможность проверить данные. Число репозиториев полезнее, если к нему прилагаются примеры мест вызова и распределение по версиям. В результатах также нужно указывать, какие коммиты были проиндексированы, насколько актуальны индексы потребителей и не были ли данные усечены. Иначе вывод «использований не найдено» можно ошибочно принять за доказательство того, что изменение никого не затронет.
  • Разделяйте анализ использования и совместимости в разных языках. Благодаря SCIP Quasar может находить ссылки на символы в нескольких экосистемах. Чтобы определить, является ли изменение API несовместимым, нужны правила совместимости или надёжный сигнал от инструмента на стороне разработчика библиотеки для соответствующей экосистемы.
  • Предоставляйте данные разработчику библиотеки, пока варианты действий ещё открыты. Результаты проверки pull request могут побудить разработчика сохранить API, опубликовать план перехода или согласовать действия с потребителями до слияния изменений. Если те же данные появятся непосредственно в рабочем процессе разработки, они смогут повлиять на изменения ещё раньше. После выпуска они по-прежнему помогут найти потребителей, которым нужно перейти на новую версию.

Сегодня Quasar индексирует код на JVM, Go, Python, JavaScript/TypeScript и Rust для анализа использования в разных репозиториях. Система сравнивает API JVM и прослеживает изменения Protobuf через сгенерированный код Java. Разработчики библиотек могут изучать результаты анализа изменений через API REST и GraphQL или сервер MCP Quasar, а затем исследовать затронутые репозитории и места вызова. Мы развиваем эту основу, добавляя проверки совместимости с учётом особенностей отдельных экосистем, более глубокую интеграцию с проверкой кода и помощь агентов при миграции потребителей; решение о выпуске остаётся за разработчиком библиотеки.

Quasar используется внутри Netflix, но этот подход можно применять и в других организациях: семантически индексировать код, сохранять определения API, сравнивать их при внесении изменений, находить затронутых потребителей и сообщать о качестве данных. Разработчикам библиотек недостаточно просто вердикта о совместимости. Им нужно знать, кого может затронуть изменение, и иметь достаточно времени, чтобы принять меры до выпуска.

Связанные доклады

© Netflix Tech Blog