Семантична версія під час виправлення важливої ​​помилки


18

Наразі я керую бібліотекою, яка має багато публічного використання, і у мене виникло питання про семантичну версію . Я хочу переробити одну досить важливу частину бібліотеки, яка реалізована неправильно - і завжди була реалізована неправильно. Але це буде означати зміни до публічного API, що є важливим рішенням.

Зміна, яку я хочу внести, обертається навколо того, як використовуються ітератори. Наразі користувачі повинні це зробити:

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

Що невірно, принаймні в рідному інтерфейсі Iterator 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. Хтось має поради?


Що заважає вам зберігати відсталу сумісність?
mouviciel

На даний момент next()метод використовується для отримання поточного елемента І переміщення внутрішнього вказівника вперед. Що неправильно. next()повинен перемістити вказівник, і current()він використовується для отримання ...
hohner

6
тож у новій версії людям не варто піклуватися про повернене значення next()лише того, що є рухом покажчика, це дійсно не порушує сумісність
грохот freak

Відповіді:


29

Ви вагаєтесь, оскільки не хочете робити семантичні версії, ви хочете зробити "рекламу, що підтримує версію". Ви очікуєте, що номер версії "2.0" повідомить світові, що у вашій бібліотеці зараз є маса нових цікавих функцій, а не те, що ви змінили API. Це нормально (багато програмних компаній та / або розробників роблять це). IMHO у вас є такі варіанти:

  • дотримуйтесь семантичної версії та живіть з тим, що вам потрібно змінити номер версії на 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 Ви на місці - зараз я повністю згоден. Тепер час спробувати
зашифрувати
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.