Сборка и зависимости
Что это такое
Проект на Java собирает инструмент: он компилирует исходники, разрешает зависимости, прогоняет тесты и упаковывает результат, а решатель зависимостей скачивает библиотеки из репозитория, разрешает их собственные зависимости транзитивно и помещает весь набор в classpath. Описание сборки лежит в репозитории, поэтому процесс воспроизводим, а набор зависимостей доступен для ревью.
Почему это важно
Граф зависимостей чаще всего и преподносит сюрпризы: собственные зависимости библиотеки приходят без запроса, и две библиотеки могут требовать несовместимых версий третьей. Однако без инструмента сборки, отчёта о разрешении или файла фиксации такой конфликт обнаруживается во время работы. Ошибка называет класс, которого никто не писал. Осознанное объявление и просмотр графа превращают целую категорию загадочных отказов в список, который можно проверить на ревью.
Ключевые идеи
Сборка — это граф задач с порядком зависимостей
Компиляция зависит от разрешения зависимостей, тесты зависят от компиляции, упаковка зависит от тестов, и порядок инструмент вычисляет сам. Объявление задач, а не последовательности команд оболочки, делает возможной инкрементальную сборку: повторяются только задачи, у которых изменились входные данные; одно и то же описание даёт одни и те же шаги, поэтому проверка чистой сборки осмысленна.
разрешение зависимостей -> компиляция -> тесты -> упаковка -> публикация
Транзитивные зависимости — обычный источник конфликтов
Библиотека объявляет свои требования, и когда запрошено несколько версий, решатель выбирает одну. Какая победит, зависит от стратегии разрешения, а ответ влияет на поведение, а не только на компиляцию. Стандартный способ разобраться — посмотреть разрешённое дерево и осознанно исключить или зафиксировать версию.
Работает classpath, а не путь компиляции
Библиотека, нужная только для компиляции и отсутствующая во время работы, даёт ошибку при первом выполнении кода, который ею пользуется. Различать эти две области видимости — настоящее умение: зависимость только для компиляции служит обработчиком аннотаций или заглушкой API, а всё остальное должно присутствовать при запуске программы.
Фиксация версий делает сборки воспроизводимыми
Разрешение до последней совместимой версии означает, что сегодняшняя сборка отличается от вчерашней без единого изменения в исходниках. Фиксация прямых зависимостей и закрепление транзитивного набора там, где инструмент это поддерживает, делают артефакт воспроизводимым, а обновление — осознанным действием, а не случайностью.
Артефакты публикуются и потребляются по координатам
Библиотека опознаётся по группе, имени и версии и публикуется в репозиторий, который читают и локальные проекты, и удалённые. Эта идентичность делает объявление зависимости однозначным, а приватный репозиторий — местом для внутреннего кода. Версия-снимок по определению изменчива, и продакшен не должен от неё зависеть.
Воспроизводимая сборка включает инструментарий
Версия самого инструмента сборки, уровень языка и целевая среда выполнения влияют на артефакт. Их объявление в описании сборки убирает ещё один источник фразы «на сборочной машине собралось иначе»; в идеале это делают через обёртку, которая использует точную версию инструмента.
Практика
Посмотрите разрешённое дерево зависимостей
Запустите отчёт инструмента сборки о зависимостях для небольшого проекта и найдите путь, по которому пришла транзитивная зависимость.
Готово, когда: вы можете назвать прямую зависимость и библиотеку, принёсшую транзитивную, и сказать, какая версия победила.
Зафиксируйте и воспроизведите сборку
Соберите проект дважды из чистого состояния с зафиксированными версиями и сравните полученные артефакты.
Готово, когда: обе сборки разрешаются в одни и те же версии и дают артефакт с одинаковым содержимым.
Частые ошибки
- Динамическое разрешение зависимостей — сборка меняется без изменений в исходниках; исправить: фиксируйте версии и закрепляйте транзитивный набор.
- Зависимость только для компиляции в рабочем classpath — её поставляют без причины, либо нужной только во время работы не хватает и она отказывает позже; исправить: держите области видимости осознанными.
- Игнорирование разрешённого дерева — две библиотеки борются за третью, и победитель случаен; исправить: смотрите дерево и явно фиксируйте или исключайте.
- Зависимость от версии-снимка в продакшене — артефакт меняется под тем же именем; исправить: зависьте от выпущенных версий.
- Опора на версию инструмента, установленную у разработчика — сборка отличается от машины к машине; исправить: используйте обёртку, которая фиксирует инструмент сборки.
Что читать дальше
- Объекты и проектирование типов (05-backend-data/04-java/02-objects-and-type-design) — код, который компилирует этот процесс сборки.
- Java (05-backend-data/04-java) — экосистема, которой принадлежит этот инструментарий сборки.
- Корпоративные серверные приложения (05-backend-data/04-java/04-enterprise-backends) — конвенции фреймворков, которые обычно и лежат в собранном артефакте.