-
-
Notifications
You must be signed in to change notification settings - Fork 59
SemVer vs VerLess
Вероятность словить баг при обновлении = Сумма(частота обновления зависимости / частота ломания зависимости)
Публикуются разные версии под одним именем.
- Ломающие изменения: увеличивается мажоная версия (1.2.3 => 2.0.0)
- Рефакторинг: увеличивается минорная версия (1.2.3 => 1.3.0)
- Расширение функциональности: увеличивается минорная версия (1.2.3 => 1.3.0)
- Баг-фиксы: увеличивается версия билда (1.2.3 => 1.2.4)
- Конфликт версий: зависимости могут случайно подтянуть разные версии одного модуля, что может внести несовместимость
- Миграция: в одном модуле нельзя одновременно использовать разные версии другого модуля, модули разных версий в общем случае не могут быть реализованы друг через друга, что утяжеляет бандл в случае конфликта
- Энтропия: каждый модуль лаконичен, но в зависимостях между модулями бардак с версиями
- Автокомплит: какую версию подключил - такую версию интерфейса и подсказывает
- Фиксация ревизий: посредством лок-файлов
Версионирование в разработке нужно для воспроизводимости билдов на разных машинах в разные моменты времени.
При обновлении любой зависимости потенциально возникают баги. Если в приложении зависимости зафиксированны - можно все или часть этих багов отложить на неопределенный срок.
Обновляют редко из-за лени перед рутиной по выявлению багов, страха пропустить баг, т.к. обычно нет полезных и актуальных автотестов. При редком обновлении, сваливается куча апдейтов, приходится решать, что пофиксить у себя, на что написать багреп или pr разрабу либы, что оставить зафиксированным.
Версионирование заходит, когда есть куча разрабов с низкой квалификацией, которые не пишут тесты или перекладывают эту задачу на более дешевых тестеровщиков. Т.к. тестировщики вручную могут тестить только перед релизом, а не после каждого билда на любой машине, то приходится фиксить версии и обновлять редко и выборочно. Такой способ обычно продвигают в компаниях, делающих ставку на кол-во и усредненность (аджайл, скрам).
Оно же принцип Открытия/Закрытия. Совместимые версии публикуются под одним именем, несовместимые - под разными.
- Ломающие изменения: публикуется под новым именем (module2 => module3)
- Рефакторинг: публикуется под тем же именем (module2 => module2)
- Расширение функциональности: публикуется под тем же именем (module2 => module2)
- Баг-фиксы: публикуется под тем же именем (module2 => module2)
- Конфликт версий: если зависимостям нужны несовместимые интерфейсы, то грузятся разные модули, которые могут быть реализованы через друг-друга и не иметь проблем с совместимостью
- Миграция: можно использовать разные версии интерфейса ибо они находятся в разных модулях, реализация старого интерфейса может использовать новую реализацию (или наоборот), что предотвращает дублирование в случае конфликта
- Энтропия: в одном пакете может быть несколько модулей с похожими именами (module, module2, module3) - либо терпеть, либо периодически создавать пакет с новым именем (pack2/module3 -> pack3/module)
- Автокомплит: так как можно использовать несколько версий интерфейса, то все варианты и предлагает
- Фиксация ревизий: посредством системы контроля версий
Безверсионность нужна, что б всегда получать билд с актуальными на момент сборки зависимостями и часто, но по-немногу фиксить наведенные от них баги.
Постоянная актуализация защитит от сценариев, когда долго не обновлялись зависимости, а потом нашли багу, в апстриме либы она пофикшена, но что б обновиться на него, надо много и долго рефакторить. Часто проблемы возникают в конфликте версий в зависимостях зависимостей (транзитивные зависимости) и приложения. На клиенте еще усложняется тем, что несколько версий либы увеличивают бандл и могут приводить к багам, поэтому надо следить за соответствием версий транзитивных зависимостей в либах и приложухе.
Проблема багов от зависимостей решается обязательными, при таком подходе, автотестами, тщательном выборе библиотек от аккуратных разработчиков, соблюдением принципа открытости и расширяемости апи без его ломания.
Безверсионность заходит, когда легко писать тесты, а их значимость адекватно осознается разрабами и бизнесом. Испольование низкоквалифицированных тестировщиков невозможно, т.к. результат ручного тестирования будет целиком устаревать с каждым новым билдом. Ставка на высокий уровень культуры программирования, качество и скорость за счет постоянного, но небольшого багфикса, повышения уровня ответственности за свой код, постоянной мотивации писать тесты в виде ломающихся сборок.
Версии у конкретных библиотек все же можно зафризить, если исправить баг быстро не удается. Например, код, который дого не актуализировался, при первом обновлении, скорее всего, сломается. В этом случае надо дописать тесты, локализовать сбойную либу, форкнуть, исправить, отправить пр или откатить до рабочей версии, написать issue и ждать исправления.
Некорректно сравнивать воспроизводимость сборок для конечных пользователей и для разрабов. У пользователей нет инструментов и квалификации для исправления или локализации багов. Например, установку gentoo linux из сорцов можно делать только с точным соответствием версий всех зависимостей. У разрабов же есть тесты, знание предметной области, возможность зафризить выборочно версию либы и использовать git bisect. Поэтому безверсионность применима только к разработке.
Нужно, если куча переиспользуемого кода, общих инстансов сервисов, которые нельзя разделять (как на клиенте)
Спор про версионирование vs безверсионность, связан со спором о том, что лучше: квалифицированный дорогой разраб, которого сложно найти или куча низкоквалицифированных, дешевых и легкодоступных разрабов и тестеровщиков. Решение зависит от возможностей бизнеса приспособиться к тому или иному способу управления. Подробнее см. Кадры.