В мире разработки программного обеспечения, существует страшное место, называемое "ад зависимостей". Чем больше ваша система, тем больше шанс, что в один из дней вы попадете в эту ловушку.
В системе с большим количеством зависимостей, выпуск новых пакетов может быстро превратиться в кошмар. Если зависимости слишком прочные, вы не можете обновить пакет, не обновив при этом версии всех зависимых пакетов. Если зависимости слишком свободные, у вас возникнут проблемы с распущенностью версий. "Ад зависимостей", это когда слишком прочные, или наоборот, слишком свободные зависимости не дают вам легко и безопасно развивать ваш проект.
Как решение этой проблемы, я предлагаю простой набор правил, которые диктуют как присваивать и увеличивать номера версий. Для того, что бы система работала, для начала, вам нужно объявить открытый API. Это должен быть простой и ясный документ. Рассмотрим немер версии в формате X.Y.Z (Major.Minor.Patch). При исправление ошибок не затрагивающих API увеличивается Patch версия. При добавление или изменение API с сохранением обратной совместимостью увеличивается Minor версия. Если API изменяется без сохранения обратной совместимости, то увеличивается Major версия.
Я называю эту систему "Семантическое управление версиями". Согласно этой схеме, номера версий и то, как они меняются несут в себе смысл об основном коде и о том, как он изменялся от версии к версии.
Ключевые слова "ДОЛЖЕН (MUST)", "НЕ ДОЛЖЕН (MUST NOT)", "СЛЕДУЕТ (SHOULD)", "НЕ СЛЕДУЕТ (SHOULD NOT)", "МОЖЕТ (MAY)", в этом документе должны интерпретироваться в соответствии с RFC 2119.
-
Программный продукт использующий Семантическое управление версиями ДОЛЖЕН иметь открытый API. Это API должно быть объявлено внутри кода или в прикладной документации. API должно быть точным и исчерпывающим.
-
Номер версии ДОЛЖЕН состоял из X.Y.Z, где X, Y, и Z это положительные числа. X это Major версия, Y это Minor версия и Z это Patch версия. Каждый элеме ДОЛЖЕН увеличиваться с шагом один. Например: 1.9.0 -> 1.10.0 -> 1.11.0.
-
Когда Major версия увеличивается, Minor и Patch версии ДОЛЖНЫ обнуляться. Когда Minor версия увеличивается, Patch версия должны обнуляться. Например: 1.1.3 -> 2.0.0 и 2.1.7 -> 2.2.0.
-
После того как версия пакета выпущена, в этот пакет НЕ ДОЛЖНО вноситься никаких изменений. Все изменения ДОЛЖНЫ выпускаться с новой версией.
-
В начале разработки Major версия равна нулю (0.y.z). В этот период, что нибудь может измениться в любое время. Открытое API НЕ ДОЛЖНО считаться стабильным.
-
Версия 1.0.0 определяет открытое API. То, как изменяется номер версии, зависит от этого открытого API.
-
Patch версия Z (x.y.Z | x > 0) ДОЛЖНА быть увеличена только если исправления ошибок имеют обратную совместимость с предыдущими версиями. Исправление ошибок устраняет некорректное поведение.
-
Minor версия Y (x.Y.z | x > 0) ДОЛЖНА быть увеличена если внесены исправления, совместимые с предыдущими версиями. Minor версия ДОЛЖНА быть увеличена если какой либо элемент API помечен как "Устаревший". Minor версия МОЖЕТ быть увеличена, при наличии существенных новых функциональных возможностей или улучшений. Minor версия МОЖЕТ включать изменения Patch версии. Patch версия должна обнуляться, когда изменяется Minor версия.
-
Major версия X (X.y.z | X > 0) ДОЛЖНА быть увеличена если внесены исправления, несовместимые с предыдущими версиями. Major версия МОЖЕТ включать изменения Minor и Patch версий. Patch и Minor версии должны обнуляться, когда изменяется Major версия.
-
Предварительные версии МОГУТ быть обозначены тире и идентификатором, разделенным точками, сразу после Patch версии. Идентификатор ДОЛЖЕН содержать символы [0-9A-Za-z-]. Предварительная версия имеет меньший приоритет, чем такая же нормальная версия. Примеры: 1.0.0-alpha, 1.0.0-alpha.1, 1.0.0-0.3.7, 1.0.0-x.7.z.92.
-
Версия сборки МОЖЕТ быть обозначена знаком плюс и идентификатором, разделенным точками, сразу же после версии Patch или предварительной версии. Идентификатор ДОЛЖЕН содержать символы [0-9A-Za-z-]. Версия сборки имеет больший приоритет, чем такая же нормальная версия. Примеры: 1.0.0+build.1, 1.3.7+build.11.e0f985a.
-
Приоритет ДОЛЖЕН рассчитываться путем разделения на Major, Minor, Patch, предварительные и сборочные версии. Major, Minor и Patch версии всегда содержат цифры. Предварительные и сборочные версии ДОЛЖНЫ быть отсортированы путем сравнения каждого идентификатора разделенного точкой по следующей схеме: Идентификаторы содержащие только цифры сравниваются числено, содержащие буквы по порядку указанному в ASCII. Численные идентификаторы всегда имеют меньший приоритет чем буквенные. Примеры: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0-rc.1+build.1 < 1.0.0 < 1.0.0+0.3.7 < 1.3.7+build < 1.3.7+build.2.b8f12d7 < 1.3.7+build.11.e0f985a.
Это не новая или революционная идея. На самом деле, вы уже наверное делали, что то похожее. Проблема в том, что "похожее" не является достаточно хорошим. Без соответствия какой-то формальной спецификации, номера версий по существу бесполезны для управления зависимостями. Давая ясные и в меру гибкие определения, вы облегчаете взаимодействие пользователей с вашим продуктом.
Простой пример, который покажет как Семантическое управление версиями поможет избежать ада зависимостей. Рассмотрим библиотеку с названием "Firetruck". Она зависим от пакета с названием "Ladder". Когда создали Firetruck, версия Ladder была 3.1.0. Так как Firetruck использует различные методы которые были представлены в 3.1.0, вы можете спокойно обновлять Ladder до версии больше чем 3.1.0 но меньше чем 4.0.0. Теперь, когда становятся доступными версии 3.1.1 и 3.2.0 пакета Ladder, вы можете перейти на них и знать, что они будут совместимы с существующим программным обеспечением.
Как ответственный разработчик, вы конечно захотите проверить совместимость пакетов. Реальность может быть жестокой, мы ничего не можем сделать с этим. Что мы можем сделать, так это позволить Семантическому управлению версиями предоставить вам простой способ обновления пакетов. Это сохранит ваше время и нервы.
Если вам понравилась идея Семантического управления версиями, вам нужно просто следовать правилам изложенным здесь. Вы можете разместить в README файле вашего проекта ссылку на эту документацию, что бы ваши коллеги, а так же люди использующие ваш продукт, так же следовали Семантическому управлению версиями.
Проще всего, это начать с версии 0.1.0 и затем увеличить номер версии для каждого последующего релиза.
Если ваш продукт начали использовать конечные потребители, он должен иметь версию 1.0.0. Если у вас есть стабильное открытое API, вы должны перейти на 1.0.0. Если вы переживаете об обратной совместимости, вы должны перейти на 1.0.0.
Нулевая Major версия, это все что вам нужно. Если ваше открытое API меняется каждый день, вы должны находиться в версии 0.x.x или работать над следующей Major версией.
Если даже мельчайшие изменения не имеют обратной совместимости, не буду ли я в скором времени в версии 42.0.0?
Это вопрос ответственного развития и предвидения. Несовместимые изменения не должны вноситься маленькими порциями в код, у которого есть много зависимостей. Расходы на обновление могут быть слишком значительными.
Это ваша ответственность, как профессионального разработчика, создающего продукт предназначенный для использования другими людьми. Управление программным обеспечением является сложной и чрезвычайно важной частью поддержания эффективности проекта.
Как только вы поняли, что вы сломали Семантическое управление версиями, вы должны зафиксировать проблему и выпустить новую версию, которая исправляет проблемы и восстанавливает обратную совместимость.
Это допустимо, если не как не влияет на открытое API. Продукт который явно зависит от вашего пакета должен иметь свою спецификацию зависимостей и автор заметит конфликт.
Устаревшая функциональность, это нормально и часто приходится прибегать к ней, для того, что бы двигаться вперед. Когда вы помечаете как устаревшую часть вашего открытого API, вы должны сделать две вещи: (1) обновить документацию, (2) выпустить хотя бы один релиз поддерживающий как новую, так и устаревшую функциональность, что бы пользователи успели плавно перестроиться.
Автор Семантическое управление версиями Tom Preston-Werner, создатель Gravatars и соучредитель GitHub.
Для того что бы высказать ваши вопросы и пожелания создайте вопрос на GitHub
Creative Commons - CC BY 3.0 http://creativecommons.org/licenses/by/3.0/