openjdk.ruOpenJDK на русском

JEP 14: The Tip & Tail Model of Library Development

Модель разработки библиотек tip & tail

AuthorsAlex Buckley, Brian Goetz, & Ron Pressler
ОтветственныйAlex Buckley
ТипInformational
ОбластьJDK
СтатусActive
Обсуждениеjdk dash dev at openjdk dot org
РецензентыAlan Bateman, Mark Reinhold, Paul Sandoz
Создан2024/09/30 23:14
Обновлён2025/02/24 23:14
Задача8341287

Аннотация

Tip & tail — это модель выпусков для программных библиотек, которая делает работу разработчиков приложений удобнее и помогает разработчикам библиотек быстрее внедрять новшества. Tip-выпуск библиотеки содержит новые возможности и исправления ошибок, а tail-выпуски содержат только исправления критических ошибок. Из tip в tail-ветки переносится как можно меньше. JDK использует tip & tail с 2018 года. Так новые возможности выходят быстрее, а пользователи, которым важна стабильность, получают надёжные и предсказуемые обновления.

Цели

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

  • Учесть, что разработчики приложений по-разному оценивают, какие изменения требуют обновления библиотек и JDK.

  • Сделать так, чтобы разработчикам библиотек не приходилось выбирать между поддержкой пользователей старых версий JDK и использованием новых возможностей (Virtual Threads (виртуальные потоки), шаблоны и т. д.), которые привлекают пользователей новых версий JDK.

  • Не ограничивать циклы выпусков библиотек, схемы версий и выбор инструментов.

Мотивация

В экосистеме Java есть богатый набор библиотек, и большинство из них разрабатывается по одной и той же модели выпусков: «один размер на всех» (one size fits all). В этой модели разработчики библиотек включают в каждый выпуск целый спектр обновлений — новые возможности, функциональные улучшения, исправления ошибок, исправления безопасности, улучшения производительности и т. д. — и ожидают, что все пользователи рано или поздно перейдут на новый выпуск.

Всеохватный подход модели «один размер на всех» позволяет библиотеке быстро развиваться на ранних этапах её жизненного цикла и помогает ей найти пользователей среди разработчиков приложений или других библиотек. Сам JDK много лет следовал такой модели. Однако когда у библиотеки становится много пользователей, их потребности становятся разнообразными и даже противоречивыми. Одни пользователи работают над системами, которые активно разрабатываются. Им нужны новые возможности и функциональные улучшения, и ради них они готовы обновляться. Другие пользователи работают над уже развёрнутыми системами. Им нужно как можно меньше изменений, и обновляться они будут только ради исправлений критических ошибок и исправлений безопасности.

На платформе Java построено очень много долгоживущих систем, поэтому вторая группа пользователей, для которых важна стабильность, огромна. Когда у библиотеки, разрабатываемой по модели «один размер на всех», выходит новый выпуск, перед такими пользователями встаёт трудный выбор: взять его и рисковать сбоем из-за множества разнообразных изменений или не брать и рисковать взломом из-за отсутствия последних исправлений? Для этих пользователей нежелание обновляться рационально, даже если оно кажется странным разработчикам в командах, где принято держаться на последних версиях. В конце концов пользователям, для которых важна стабильность, неизбежно понадобится исправление, которое есть только в гораздо более новом выпуске, и обновление, скорее всего, будет болезненным.

Кроме того, модель «один размер на всех» означает, что библиотека должна поддерживать широкий диапазон версий JDK. Большинство библиотек выбирают наименьший общий знаменатель — базовую версию, обычно JDK 8, — и поэтому могут использовать только возможности Java, доступные в базовой версии. Это разочаровывает пользователей, создающих новые системы: они хотят, чтобы библиотеки повышали продуктивность разработчиков за счёт современных возможностей Java, таких как Records (записи), Sealed Classes (запечатанные классы), Pattern Matching (сопоставление с образцом) и Foreign Function & Memory API.

А как же семантическое версионирование?

Семантическое версионирование — это схема, с помощью которой разработчики библиотек показывают, содержат ли новые версии крупные изменения, небольшие изменения или только исправления ошибок. Значит ли семантическое версионирование, что пользователи, которые приветствуют изменения, могут их получить, а пользователи, которым нужна стабильность, могут их избежать? К сожалению, нет. Семантическое версионирование различает новую функциональность (увеличивается старший или младший номер версии) и исправления ошибок (увеличивается номер патча), но в модели «один размер на всех» пользователи не могут получить одно без другого. Например, допустим, в версии 2.1 библиотеки есть ошибки, которые исправлены в версиях 2.1.1 и 2.1.2 в соответствии с семантическим версионированием. Эти обновления отвечают потребностям пользователей, для которых важна стабильность, но в модели «один размер на всех» разработка 2.1.x неизбежно прекратится, когда выйдет версия 2.2 или 3.0 с небольшими и крупными изменениями соответственно, которые этим пользователям не нужны.

Каскад катастроф

Независимо от того, использует ли библиотека семантическое версионирование, обновления часто приносят изменения в зависимостях библиотеки. В результате могут подтянуться крупные обновления, которые разочаровывают пользователей, для которых важна стабильность. Например, хотя версия 2.1.1 библиотеки содержит только исправления ошибок, она может обновить зависимость от другой библиотеки с 3.1 до 3.2 ради функциональных улучшений, а версия 3.2 той библиотеки может обновить свою зависимость от ещё одной библиотеки с 4.x до 5.x, чтобы получить крупные новые возможности. Пользователи, для которых важна стабильность, при переходе на 2.1.1 увидят, что изменилось всё дерево зависимостей, хотя им нужны были только исправления ошибок в одной библиотеке и ничего больше.

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

А как же несколько веток выпусков?

Вместо модели «один размер на всех» некоторые библиотеки используют несколько веток выпусков, чтобы удовлетворить разные группы пользователей. Обычно это крупные фреймворки — Spring, Lucene, Cassandra и т. д., — которые существенно развиваются, и в результате выходят их новые старшие версии. Их разработчики понимают, что некоторые пользователи не могут или не хотят переходить на эти версии. Поэтому они создают новую ветку выпусков для каждой старшей версии и делают её базовой версией более новую версию JDK, а для старых старших версий выпускают обновления в ветках, базовой версией которых служат более старые версии JDK. Например, для Spring Framework 5.x базовая версия — JDK 8, а для 6.x — JDK 17.

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

Путь вперёд: разработка по модели tip & tail

Мы считаем, что существует модель выпусков библиотек, которая лучше отвечает потребностям экосистемы Java, чем модель «один размер на всех» и модель с несколькими ветками, и при этом обходится разработчикам библиотек дешевле. Модель tip & tail — это упрощённая и дисциплинированная форма модели с несколькими ветками. Она даёт пользователям, для которых важна стабильность, именно то, что им нужно, — исправления ошибок и исправления безопасности и ничего больше. А пользователи, создающие новые системы, получают то, чего хотят, — новые возможности и улучшения, причём быстрее. Так платформа Java остаётся привлекательным выбором для новых приложений, а будущее существующих приложений защищено.

Описание

Модель разработки библиотек tip & tail — это упрощённая и дисциплинированная форма модели с несколькими ветками, в которой почти вся работа ведётся только в одной ветке выпусков.

В модели tip & tail разработчики библиотек ведут ветку выпусков, которая называется tip. Выпуски в ветке tip нужны для движения вперёд: они повышают продуктивность пользователей, создающих новые системы, за счёт новых возможностей и функциональных улучшений, а также максимально возможного набора исправлений ошибок, исправлений безопасности и улучшений производительности. Время от времени разработчики библиотеки объявляют один из tip-выпусков началом новой tail-ветки, которую они продолжат обновлять и после выхода новых tip-выпусков. Выпуски в tail-ветке нужны для сохранения статус-кво: они отвечают потребностям пользователей, для которых важна стабильность, и содержат исправления критических ошибок и исправления безопасности — и ничего больше.

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

  • Добавлять новые возможности и функциональные улучшения только в tip, а не в tail-ветки.

  • Переносить из tip в tail-ветки как можно меньше.

  • Следить, чтобы tail-выпуски зависели от tail-выпусков других библиотек, если они есть.

Каждая библиотека, перешедшая на tip & tail, немного упрощает жизнь своим пользователям. Пользователи, для которых важна стабильность, могут переходить с одного tail-выпуска на другой и получать только исправления ошибок и исправления безопасности. Если зависимости библиотеки на всех уровнях используют tip & tail, это вызовет каскад обновлений, каждое из которых содержит только исправления ошибок и исправления безопасности. В самом низу дерева зависимостей находится JDK, который перешёл на tip & tail в 2018 году, поэтому пользователи, для которых важна стабильность, могут получать tail-выпуски только с исправлениями ошибок и исправлениями безопасности, например JDK 17.0.x и JDK 21.0.y. Чем больше библиотек переходят на tip & tail, тем согласованнее становится экосистема Java: пользователи, создающие новые системы, будут использовать tip-выпуски библиотек и JDK, а пользователи, для которых важна стабильность, — tail-выпуски библиотек и JDK.

Переносить как можно меньше

Именно дисциплина «переносить как можно меньше» отличает модель разработки библиотек tip & tail от традиционных моделей с несколькими ветками. Она означает, что из ветки tip в tail-ветки переносятся только исправления критических ошибок, то есть ошибок, из-за которых приложения могут катастрофически сбоить (например, неправильные математические вычисления), и исправления уязвимостей безопасности.

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

Кроме того, принцип «переносить как можно меньше» означает, что tip & tail часто требует меньше работы, чем модель «один размер на всех». Разработка в ветке tip может опираться на функционально богатые tip-выпуски своих зависимостей, включая JDK, и ей не нужно заботиться о старых версиях зависимостей или о работе на старых версиях JDK. Это с лихвой окупает небольшой объём работы («переносить как можно меньше»), необходимый для поддержки tail-веток.

Вот пример временной шкалы tip & tail с двумя tail-ветками:

TIP:    1.0 -- 2.0 -- 2.1 -- 3.0 -- 3.1 -- 4.0 -- 4.1 -- 4.2 -- 5.0 ...
                       \             \
                        \             \      
TAIL 1:                  \- 2.1.1 -------- 2.1.2 -- 2.1.3 -- 2.1.4 -- 2.1.5 EOL
                                        \
                                         \
TAIL 2:                                   \- 3.1.1 -- 3.1.2 -- 3.1.3 -- ...

Любому разработчику библиотек, знакомому с несколькими ветками выпусков, это покажется ничем не примечательным, потому что влияние tip & tail заметно только в содержимом tail-веток:

  • В tail-ветке 2.1.x нет возможностей и улучшений из 3.0 и более поздних версий.

  • В tail-ветке 3.1.x нет возможностей из 4.0 и более поздних версий.

  • Обе tail-ветки содержат (применимые к ним) исправления безопасности из всех tip-выпусков вплоть до 5.0 включительно.

Помимо минимизации бэкпортов, tip & tail оставляет разработчикам библиотек много свободы:

  • Tip & tail не определяет, когда и зачем создаются tail-ветки, а также когда и почему их поддержка прекращается.

  • Tip & tail не ограничивает цикл выпусков библиотеки. Например, новый tip-выпуск может выходить по регулярному графику (time-boxed, с фиксированным сроком) или при добавлении значимой возможности (feature-boxed, по готовности возможностей), а новый tail-выпуск — по регулярному графику, либо когда перенесено пороговое число исправлений ошибок, либо когда исправлено пороговое число серьёзных CVE.

  • Tip & tail не предписывает ни схему нумерации версий, ни использование меток alpha/beta/Release Candidate (кандидат в релизы), ни какие-либо другие метаданные библиотеки.

Не переносите новые возможности и улучшения производительности

Эффективность tip & tail основана на том, чтобы переносить из tip-ветки в tail как можно меньше: только исправления критических ошибок и исправления безопасности.

Неизбежно некоторые пользователи будут просить перенести новые возможности или функциональные улучшения из tip-ветки, потому что они используют tail-выпуски и не могут или не хотят переходить на tip-выпуски. Однако желание получить новые возможности или функциональные улучшения означает, что они активно развивают свой код, и tip-выпуски, как правило, подошли бы им хорошо. Это противоречие, и его причины обычно индивидуальны, например корпоративная политика, выбор инструментов и численность персонала. Разработчикам библиотек следует помнить, что время, потраченное на бэкпорты, — это время, не потраченное на развитие tip-ветки, а значит, это вредит пользователям, создающим новые системы. Перенос новых возможностей и функциональных улучшений также рискует дестабилизировать tail-ветку и тем самым навредить пользователям, ориентированным на стабильность, ради которых tail-ветка и существует.

Точно так же некоторые пользователи будут просить перенести из tip-ветки исправления некритических ошибок. Однако перенос даже самого маленького исправления ошибки влечёт накладные расходы, которые увеличивают стоимость сопровождения tail-веток: тестирование, документация, управление выпусками (должны ли исправление получить все tail-ветки, или только одна, или некоторые?) и т. д. Кроме того, любое исправление ошибки может повлиять на поведение чьего-то кода (один опытный разработчик JDK однажды заметил: «Любое изменение — несовместимое изменение»). Пользователи, ориентированные на стабильность, хотят, чтобы их код вёл себя одинаково год за годом, и, рассчитывая получать в tail-ветках только исправления критических ошибок, они могли давно обойти ошибку, и её исправление им бы навредило. Разработчикам библиотек следует описать в документации признаки исправления «критической» ошибки, чтобы предложения о переносе исправлений можно было оценивать быстро и единообразно, сводя к минимуму время, вкладываемое в tail-ветки.

У разработчиков библиотек может возникнуть соблазн перенести улучшения производительности из tip-ветки. Хотя некоторые пользователи, ориентированные на стабильность, возможно, и готовы принять риск, связанный с этими изменениями, все пользователи, ориентированные на стабильность, могут обойтись без них. Отказ от переноса улучшений производительности вряд ли заставит пользователей, ориентированных на стабильность, отказаться от библиотеки, потому что переход на другую библиотеку был бы ещё рискованнее, чем обновление до tip-версии текущей библиотеки. Возможны исключения, например перенос небольшого улучшения производительности, которое сильно локализовано и и очевидно несёт мало риска. Однако, поскольку эффективность tip & tail основана на низкой стоимости сопровождения tail-веток, такие исключения следует сводить к минимуму.

Выбор базовой версии JDK

Поскольку tip-выпуски библиотеки ориентированы на другую аудиторию, чем её tail-выпуски, базовая версия JDK для tip-выпусков может отличаться от базовой версии JDK для tail-выпусков. Мантра для разработчиков библиотек такова:

  • В tip-ветке выбирайте для каждого tip-выпуска базовую версию JDK, которая лучше всего поддерживает новые возможности и улучшения библиотеки. Базовой может быть самая свежая версия JDK, если, например, в ней есть новый API, который значительно улучшает реализацию библиотеки. Или же базовой может быть более старая версия JDK, получившая статус выпуска Long-Term Support (долгосрочная поддержка), например JDK 21.

  • Выбирайте для tail-ветки базовую версию JDK, получившую статус выпуска Long-Term Support. Сохраняйте базовую версию как можно более неизменной на протяжении всего существования tail-ветки.

Вот снова пример временной шкалы tip & tail, на этот раз с указанием базовой версии JDK, выбранной для каждого выпуска (в скобках):

TIP:    1.0 -- 2.0 -- 2.1 -- 3.0 -- 3.1 -- 4.0 -- 4.1 -- 4.2 -- 5.0 ...
        (11)   (17)   (17)   (19)   (21)   (22)   (24)   (26)   (28)
                       \             \
                        \             \    
TAIL 1:                  \- 2.1.1 -------- 2.1.2 -- 2.1.3 -- 2.1.4 -- 2.1.5 EOL
                             (17)       \    (17)    (17)     (17)     (17) 
                                         \
                                          \
TAIL 2:                                    \- 3.1.1 -- 3.1.2 -- 3.1.3 -- ...
                                                (21)     (21)     (21)

Эта временная шкала показывает:

  • Необязательно выпускать tip-версии синхронно с шестимесячными tip-выпусками JDK. Выше, после того как версия 2.0 была основана на JDK 17, разработчики библиотеки выпускают tip-версии раз в год; как правило, в результате базовой становится каждая вторая версия JDK.

  • Обычно базовую версию JDK tip-ветки повышают, когда библиотеке нужны новые возможности JDK. Выше разработчики библиотеки хотели использовать Foreign Function & Memory API, появившийся в JDK 22, поэтому сделали tip-выпуск на базе JDK 22 и повысили версию с 3.1 до 4.0. Они также ответвили от 3.1 tail-ветку для приложений, которые не могут перейти на JDK 22.

  • Разумно выбирать для tail-веток базовые версии JDK, которые авторитетные поставщики обозначили как выпуски Long-Term Support (LTS). Выше разработчики библиотеки ответвили tail-ветки от 2.1 и 3.1, потому что эти tip-выпуски основаны на JDK 17 и 21, которые обозначены как выпуски LTS. Было бы неразумно ответвлять tail-ветку от 3.0, потому что её базовая версия, JDK 19, не обозначена как выпуск LTS.

Когда tail-ветка библиотеки основана на версии JDK, у которой есть tail-ветка, пользователи, ориентированные на стабильность, могут рассчитывать на поток консервативных обновлений библиотеки и её зависимостей, включая JDK. Например, если tail-ветка 2.1.x основана на JDK 17, пользователи 2.1.x могут обновиться до последнего выпуска JDK 17.0.y и получить исправления критических ошибок. Однако неизбежно, что некоторые пользователи будут запускать 2.1.x на более новых JDK, таких как 21 или 25, и сообщать о проблемах разработчику библиотеки. На самом деле эти пользователи говорят, что ожидают от разработчика библиотеки тестирования каждого выпуска 2.1.x на многих версиях JDK, а не только на JDK 17. Это ожидание несправедливо: разработчики библиотек, как правило, предпочитают тратить время на работу над tip-выпусками, а не на тестирование матрицы tail-выпусков и версий JDK. Поскольку tip & tail сохраняет низкую стоимость сопровождения tail-веток, разработчик библиотеки может позволить себе предлагать tail-ветку 2.1.x для пользователей JDK 17 и tail-ветку 3.1.x для пользователей JDK 21.

Успех tip & tail

Java-библиотека с самой разнообразной аудиторией пользователей — это сам JDK. Чтобы обслуживать миллионы разработчиков, JDK исторически использовал модель с несколькими ветками: основной выпуск выходил раз в несколько лет, и за каждым следовал поток минорных выпусков раз в несколько месяцев. Например, за JDK 8 в 2014 году последовали десятки выпусков JDK 8uXX в течение следующих пяти лет. Хотя эта модель существовала десятилетиями, у неё были серьёзные недостатки:

  • Основные выпуски зависели от крупных новых возможностей языка Java и API, из-за чего были подвержены непредсказуемым задержкам. Пользователям, создающим новые системы и желающим нововведений, приходилось годами ждать, прежде чем они могли воспользоваться такими возможностями, как лямбда-выражения и Stream API.

  • Минорные выпуски не могли изменять язык Java или API, но добавляли и изменяли значимые возможности среды выполнения Java. Например, JDK 7u40 добавил Java Flight Recorder (JFR), что означало значительное изменение реализации в JVM, а JDK 8u20 изменил общеизвестное расположение исполняемых файлов JDK, сломав сторонние скрипты.

  • Многие минорные выпуски действительно содержали только исправления безопасности, но их неизбежно заменял универсальный минорный выпуск, содержавший и исправления безопасности, и новые возможности. Например, у пользователей, которых устраивал JDK 8u5, после выхода JDK 8u20 не было способа получать только исправления ошибок и исправления безопасности, а также административные обновления, например данные о часовых поясах. Многие пользователи решили остаться на более старых, проверенных минорных выпусках, чтобы избежать постоянных изменений в новых минорных выпусках, даже рискуя оказаться уязвимыми для новых эксплойтов.

Недовольство как пользователей, стремящихся к нововведениям, так и пользователей, стремящихся к стабильности, стало причиной смены модели выпусков после JDK 9. В 2018 году сообщество OpenJDK приняло модель tip & tail для дальнейшей разработки JDK, начиная с JDK 10. Шесть лет спустя модель хорошо работает:

  • Новые возможности и улучшения языка Java и API добавляются только в tip-ветку. Разработка в tip-ветке идёт с фиксированным сроком (time-boxed): новый tip-выпуск выходит каждые шесть месяцев — JDK 18 и 19 в 2022 году, JDK 20 и 21 в 2023 году и так далее. Tip-выпуски называются Feature Release (функциональный выпуск). Пользователи, создающие новые системы, получают выгоду от быстрого потока нововведений в выпусках Feature Release.

  • От каждого tip-выпуска JDK ответвляется tail-ветка. Бэкпорты в tail-ветки — это в основном исправления безопасности и исправления ошибок с низким риском. Разработка в tail-ветках идёт с фиксированным сроком: новый tail-выпуск выходит каждые три месяца — 18.0.1, 18.0.2 и так далее. Tail-выпуски называются update releases (выпуски обновлений).

  • Большинство поставщиков JDK обозначили версии JDK 8, 11, 17 и 21 как выпуски Long-Term Support (LTS). Это означает, что поставщики переносят исправления в эти tail-ветки в течение многих лет и выпускают выпуски обновлений каждый январь, апрель, июль и октябрь. Пользователи, ориентированные на стабильность, получают от этих выпусков обновлений желаемую низкую интенсивность изменений.

  • Для остальных версий JDK нормой являются два выпуска обновлений, после чего сопровождение tail-ветки прекращается, потому что в tip-ветке выходит новый выпуск (то есть новый Feature Release). Пользователи, которые хотят быть в курсе новых возможностей и/или получать максимально полный набор улучшений производительности, исправлений ошибок и исправлений безопасности, могут делать это, запуская каждый Feature Release и два его выпуска обновлений: JDK N, JDK N.0.1, JDK N.0.2, затем JDK N+1, JDK N+1.0.1, JDK N+1.0.2 и т. д. Неформально удобно говорить, что эти пользователи используют tip JDK, хотя выпуски обновлений *.0.1 и *.0.2 технически относятся к tail-ветке.

  • Как и любое изменение процесса, переход на новую модель выпусков требует изменения мышления и обычно встречает скептицизм, особенно опасение, что он потребует больше работы. Разработчики JDK поначалу тоже высказывали такой скептицизм, но следование мантре минимальных бэкпортов привело к заметному сокращению трудозатрат.

Spring Boot — пример библиотеки, которая перешла на модель tip & tail. Новые возможности добавляются только в tip-ветку; в tail-ветки переносятся только исправления ошибок. Разработка в tip-ветке ограничена по времени: новый tip-выпуск выходит каждые шесть месяцев: Spring Boot 2.7 и 3.0 в 2022 году, Spring Boot 3.1 и 3.2 в 2023 году и так далее. От tip-выпусков регулярно ответвляются tail-ветки, которые, как правило, существуют недолго. Однако tip-выпуск, завершающий поколение, например Spring Boot 2.7, становится корнем tail-ветки, которая сопровождается гораздо дольше.

Q & A

Если я как разработчик библиотеки ориентирую свои tip-выпуски на JDK 21, не брошу ли я своих пользователей на JDK 8 и 17?

Нет, потому что вы можете почти без усилий предоставить этим пользователям tail-выпуски, ориентированные на JDK 8 и 17. Если переносить как можно меньше, сопровождение tail-ветки обходится дёшево, поэтому разработчики библиотек могут позволить себе чаще ответвлять tail-ветки и дольше их обновлять.

Я как разработчик библиотеки уже веду несколько веток выпусков библиотеки; значит, я следую модели tip & tail?

Несколько веток выпусков необходимы для модели tip & tail, но недостаточны. Главное — переносить в старые ветки как можно меньше. Это означает говорить «нет» участникам и пользователям, которые хотят, чтобы исправления переносились активнее.

Риски и допущения

  • Для упрощения мы провели чёткую границу между пользователями, создающими новые системы, и пользователями, ориентированными на стабильность. В действительности большинство пользователей ориентированы на то и другое: одни части их кода меняются, а другие стабильны. Для меняющейся части пользователям следует выбирать tip-выпуски её зависимостей; для стабильной части — tail-выпуски её зависимостей. Например, приложение может использовать tip-выпуск веб-фреймворка и tail-выпуск библиотеки планирования заданий.

  • Риск перехода на модель tip & tail в том, что некоторые пользователи держатся за универсальную модель: они ценят стабильность tail-выпусков, но при этом ожидают, что часть новых возможностей и улучшений из tip-выпуска будет перенесена в tail-выпуски. Хотя эти пользователи могут не считать себя сторонниками передовых технологий, лучший вариант для них — использовать tip-выпуск: он даёт нужные им новые возможности и улучшения и включает все необходимые им исправления ошибок и исправления безопасности. Tip-выпуски хорошо сопровождаемой библиотеки так же стабильны, как её tail-выпуски, и получают львиную долю исправлений. Например, в tip-ветку JDK попадает на порядок больше исправлений ошибок, чем в tail-ветки.