Семантическое управление версиями при исправлении важной ошибки

18

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

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

while ($element = $iterator->next()) {
   // ...
}

Что неверно, по крайней мере, в родном интерфейсе итератора PHP . Я хочу заменить на это:

while ($iterator->valid()) {
   $element = $iterator->current();
   // ...
   $iterator->next();
}

что аналогично:

foreach ($iterator as $element) {
    // ...
}

Если вы посмотрите на руководство Тома по семантическому версионированию, он ясно заявляет, что любые изменения в публичном API (то есть те, которые не являются обратно совместимыми) должны оправдать основной выпуск. Таким образом, библиотека будет перепрыгивать с 1.7.3 до 2.0.0, что для меня слишком далеко. Мы говорим только об одной исправляемой функции.

У меня есть планы в конечном итоге выпустить 2.0.0, но я подумал, что это было, когда вы полностью переписали библиотеку и внесли многочисленные изменения в публичный API. Означает ли введение этого рефакторинга выпуск основной версии? Я действительно не могу видеть, как это происходит - я чувствую себя более комфортно, выпуская его как 1.8.0 или 1.7.4. У кого-нибудь есть совет?

Hohner
источник
Что мешает вам сохранить обратную совместимость?
Mouviciel
На данный момент next()метод используется для извлечения текущего элемента и перемещения внутреннего указателя вперед. Что не так. next()должен перемещать указатель и current()используется для извлечения ...
hohner
6
поэтому в новой версии люди не должны заботиться о возвращаемом значении next()только того, что перемещает указатель, это действительно не нарушает совместимость
ratchet freak

Ответы:

29

Вы сомневаетесь, потому что вы не хотите делать семантическое версионирование, вы хотите сделать «рекламу, поддерживающую версионирование». Вы ожидаете, что номер версии 2.0 сообщит миру, что у вас есть куча новых интересных функций в вашей библиотеке, а не то, что вы изменили API. Это нормально (многие компании-разработчики программного обеспечения и / или разработчики делают это). ИМХО у вас есть следующие варианты:

  • придерживайтесь семантического управления версиями и согласитесь с тем, что вам нужно изменить номер версии на 2.0.0
  • измените свою схему управления версиями на 4 числа. «1.1.7.3» - это ваша версия, «1.2.0.0» - следующая после изменения API, и «2.0.0.0» - первая из «совершенно нового семейства продуктов 2.x».
  • сделать ваши исправления обратной совместимости (так что не изменить функциональность next, просто добавьте validи currentфункцию). Тогда вы можете использовать «1.8.0» в качестве следующего номера версии. Если вы думаете, что изменение поведения nextдействительно важно, сделайте это в 2.0.0.
Док Браун
источник
Последний вариант был бы идеальным решением: вы не можете просить next()продолжать делать то, что он делает. Чтобы правильно реализовать функциональность, нужно сделать что-то по-другому. Так что, если я сделаю его обратно совместимым - новая функциональность / исправление также будет неправильной и подорвет весь смысл изменений.
hohner
2
Лучше рассмотреть более широкое предложение, которое вы сделаете в своем третьем пункте (чтобы сделать исправление обратно совместимым). Это может не сработать в данном конкретном случае, но стоит рассмотреть общую технику. Функция оказывается более сложной, но это может быть работоспособным маршрутом.
Спасибо всем: если бы я мог принять два, я бы. В итоге я взломал новый next()метод, чтобы сделать все новые функциональные возможности, а также то, что было необходимо для обеспечения обратной совместимости. Это немного ужасно, чтобы запятнать новую функциональность, как это, но эй хо.
Hohner
10
@hohner: Теперь самое время задокументировать старое поведение как устаревшее, так что вы можете удалить его в 2.0.0.
Ян Фабри
7

Придерживайтесь руководства Тома по семантическому версионированию.

Любые существенные изменения в публичном API должны быть выполнены в любом из двух пунктов:

  1. Никогда
  2. В крупном обновлении выпуска

Мой голос, кстати, за первый. Но я признаю, что это подходит только для пустяков.

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

По сути, вы создаете ошибку индексации для своих пользователей, которые не знают об изменениях. Принудительное изменение, подобное этому, заставляет всех ваших пользователей делать следующее:

  1. Код исправления, чтобы использовать новый подход
  2. Проверьте исправление и убедитесь, что оно ничего не сломало
  3. Отправляйте новые версии своего продукта своим конечным пользователям.

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

Для чего-то такого маленького, я бы позволил этому уйти и не беспокоиться об этом.
Если это действительно беспокоит вас (что, по-видимому, так или иначе, вы бы не спросили), тогда я бы сделал следующее.

  1. Создайте ветку v2.0.0 в своем дереве кода
  2. Сделайте первый вклад в ветку v2.0.0, которая является этим изменением
  3. Отправьте предварительный просмотр, чтобы Release Notesсообщить о предстоящем изменении

А затем наберитесь терпения, так как потребуется время, чтобы накопить другие вещи, которые оправдывают обновление номера версии до нового основного выпуска. Расширенное уведомление (часть 3) дает вам время для получения отзывов от конечных пользователей, чтобы выяснить, какое влияние окажет это изменение.


Альтернативное решение - добавить новую функцию, которая работает так, как вы хотите.

Если у вас есть, foo()вы бы создали fooCorrect(), чтобы обеспечить исправление, но также полностью сохранить обратную совместимость. И в какой-то момент вы можете foo()отказаться от того, чтобы другие знали, чтобы не использовать его.

Проблема в том, что вы найдете что-то еще, в рамках fooCorrect()чего требуется его обновление, и вы в конечном итоге получите fooCorrectedCorrect()какую-то другую глупость.

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

Но это может быть «наименее плохой» подход, чтобы рассмотреть что-то маленькое.


источник
Я согласен. Проблема, с которой я сталкиваюсь, заключается в том, что я хочу полностью переписать библиотеку для v2.0.0 (потому что есть много этих проблем, которые необходимо исправить); поэтому я не хочу, чтобы такое небольшое изменение, как итераторы, составляло основу этого большого изменения. Так что мои варианты: либо игнорировать эту ошибку, либо исправить ошибку и поместить ее в новую основную версию?
Hohner
@hohner - обновленный ответ, чтобы обеспечить альтернативный подход к созданию новых функций. Имейте в виду, что множество новых функций с одинаковыми именами почти так же плохо, как и изменение самого API.
3
@hohner: последовательно неправильно> несовместимо правильно в этом случае. Поведение все еще функционирует, оно просто не идиоматично. Учтите, что если вы сделаете это изменение, вы нарушите клиентский код. Делать это без предупреждения не оценят.
Фоши
@ GlenH7 В этом случае использование альтернативно названного метода не будет работать. Нативный итератор PHP использует эти методы (то есть, next()нет nextCorrect()). Я посмотрю, смогу ли я изменить next (), чтобы он был обратно совместим и работал при реализации Iteratorинтерфейса.
Hohner
1
@Phoshi Ты на месте - теперь я полностью согласен. Теперь пришло время попробовать кодировать невозможное: D
hohner