Versi semantik saat memperbaiki bug penting

18

Saat ini saya mengelola perpustakaan yang memiliki banyak penggunaan publik, dan saya punya pertanyaan tentang versi semantik . Saya ingin memperbaiki satu bagian yang cukup penting dari perpustakaan yang diimplementasikan secara tidak benar - dan selalu diimplementasikan dengan salah. Tetapi melakukan ini berarti perubahan pada API publik, yang merupakan keputusan besar.

Perubahan yang ingin saya lakukan berkisar pada bagaimana iterator digunakan. Saat ini, pengguna harus melakukan ini:

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

Yang salah, setidaknya di antarmuka PHP asli Iterator . Saya ingin mengganti dengan ini:

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

yang analog dengan:

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

Jika Anda melihat panduan Tom untuk versi semantik, ia dengan jelas menyatakan bahwa setiap perubahan pada API publik (yaitu yang tidak kompatibel ke belakang), harus membenarkan rilis utama. Jadi perpustakaan akan melompat dari 1.7.3 ke 2.0.0 yang, bagi saya, adalah langkah terlalu jauh. Kami hanya berbicara tentang satu fitur diperbaiki.

Saya memang punya rencana untuk merilis 2.0.0, tetapi saya pikir ini adalah ketika Anda benar-benar menulis ulang perpustakaan dan mengimplementasikan banyak perubahan API publik. Apakah pengenalan refactoring ini menjamin rilis versi utama? Saya benar-benar tidak bisa melihat bagaimana caranya - saya merasa lebih nyaman melepaskannya sebagai 1.8.0 atau 1.7.4. Adakah yang punya saran?

hohner
sumber
Apa yang mencegah Anda menjaga kompatibilitas?
mouviciel
Saat ini, next()metode ini digunakan untuk mengambil elemen saat ini DAN menggerakkan pointer internal ke depan. Yang salah. next()harus menggerakkan pointer, dan current()digunakan untuk mengambil ...
hohner
6
jadi dalam versi baru orang-orang seharusnya tidak peduli tentang nilai balik next()hanya yang menggerakkan pointer, ini benar-benar tidak merusak kompatibilitas
ratchet freak

Jawaban:

29

Anda ragu karena Anda tidak ingin membuat versi semantik, Anda ingin membuat "versi pendukung iklan". Anda mengharapkan nomor versi "2.0" untuk memberi tahu dunia bahwa Anda memiliki banyak fitur keren baru di perpustakaan Anda sekarang, bukan karena Anda mengubah API. Tidak apa-apa (banyak perusahaan perangkat lunak dan / atau pengembang melakukan itu). IMHO Anda memiliki opsi berikut:

  • tetap berpegang pada semantik versi dan hidup dengan kenyataan bahwa Anda harus mengubah nomor versi menjadi 2.0.0
  • ubah skema versi Anda menjadi 4 angka. "1.1.7.3" adalah versi Anda sekarang, "1.2.0.0" yang berikutnya setelah mengubah API, dan "2.0.0.0" yang pertama dari "keluarga produk 2.x yang sepenuhnya baru"
  • buat perbaikan Anda kompatibel (jadi jangan ubah fungsionalitas next, cukup tambahkan validdan currentfungsinya). Kemudian Anda dapat menggunakan "1.8.0" sebagai nomor versi berikutnya. Jika Anda berpikir mengubah perilaku nextsangat penting, lakukanlah dalam 2.0.0.
Doc Brown
sumber
Sebanyak pilihan terakhir akan menjadi solusi sempurna: Anda tidak bisa meminta next()untuk terus melakukan apa yang dilakukannya. Untuk mengimplementasikan fungsi dengan benar, ia harus melakukan sesuatu yang berbeda. Jadi jika saya membuatnya kompatibel - fungsi baru / perbaikan juga akan salah, dan merusak seluruh titik perubahan.
hohner
2
Saran yang lebih luas yang Anda buat di bullet ketiga Anda (membuat perbaikan mundur kompatibel) adalah saran yang bagus untuk dipertimbangkan. Ini mungkin tidak berfungsi dalam kasus khusus ini, tetapi teknik keseluruhan layak dipertimbangkan. Fungsi ini akhirnya menjadi lebih kompleks tetapi ini mungkin rute yang bisa diterapkan.
Terima kasih kepada semua orang: jika saya dapat menerima dua, saya akan menerima. Saya akhirnya meretas next()metode baru untuk melakukan semua fungsi baru, ditambah apa yang diperlukan untuk membuat kompatibel. Rasanya agak mengerikan karena harus menodai fungsi baru seperti ini, tapi hei ho.
hohner
10
@ hohner: Maka sekarang juga saatnya untuk mendokumentasikan perilaku lama sebagai usang, sehingga Anda dapat menghapusnya di 2.0.0.
Jan Fabry
7

Tetap dengan panduan Tom untuk versi semantik.

Setiap perubahan signifikan pada API publik harus dilakukan di salah satu dari dua poin ini:

  1. Tidak pernah
  2. Pada pembaruan rilis utama

Pilihan saya, omong-omong, adalah untuk yang pertama. Tapi saya akui itu hanya cocok untuk hal-hal sepele.

Masalahnya adalah menjaga kompatibilitas ke belakang dan memastikan Anda tidak merusak barang-barang untuk pengguna API Anda sebelumnya.

Intinya, Anda membuat kesalahan pengindeksan untuk pengguna Anda yang tidak menyadari perubahan tersebut. Memaksa perubahan seperti ini memaksa semua pengguna Anda untuk melakukan hal berikut:

  1. Kode perbaikan untuk menggunakan pendekatan baru
  2. Validasi perbaikannya dan pastikan tidak merusak apa pun
  3. Kirim rilis baru produk mereka ke pengguna akhir mereka

Itu bisa berpotensi banyak usaha, terutama ketika Anda mempertimbangkan betapa sedikit proyek memiliki kasus uji untuk memvalidasi perubahan seperti ini. Jumlah upaya bertambah ketika Anda mempertimbangkan jumlah pengguna hilir dari pengguna Anda yang juga perlu memperbarui instalasi mereka.

Untuk sesuatu yang sekecil ini, saya akan membiarkannya pergi dan tidak repot-repot dengan itu.
Jika itu benar-benar mengganggu Anda (yang ternyata tidak atau Anda tidak akan bertanya) maka saya akan melakukan hal berikut.

  1. Buat cabang v2.0.0 di pohon kode Anda
  2. Buat kontribusi pertama ke cabang v2.0.0, yang merupakan perubahan ini
  3. Kirimkan pratinjau Release Notessebelumnya yang menyiarkan bahwa perubahan akan terjadi

Dan bersabarlah karena akan membutuhkan waktu untuk mengumpulkan hal-hal lain yang membenarkan peningkatan nomor versi ke rilis besar baru. Pemberitahuan lanjutan (bagian 3) memberi Anda waktu untuk menerima umpan balik dari pengguna akhir untuk mengetahui seberapa besar dampak perubahan yang akan terjadi.


Solusi alternatif adalah menambahkan fungsi baru yang beroperasi dengan cara yang Anda inginkan.

Jika sudah, foo()maka Anda akan membuat fooCorrect()untuk memberikan perbaikan tetapi juga sepenuhnya mempertahankan kompatibilitas ke belakang. Dan pada titik tertentu Anda dapat foo()membuat orang lain tahu untuk tidak menggunakannya.

Tantangannya ada adalah bahwa Anda akan menemukan sesuatu yang lain dalam fooCorrect()yang memerlukan pembaruan itu dan Anda berakhir dengan fooCorrectedCorrect()atau omong kosong konyol lainnya.

Jika Anda benar-benar menginginkannya ini diperbaiki sekarang, pendekatan alternatif ini mungkin merupakan rute terbaik. Waspadai dan waspada menciptakan banyak fungsi tambahan dengan cara ini karena itu membuat API lebih sulit untuk dikerjakan. Dan kesadaran itu mungkin cukup untuk mencegah yang terburuk dari jenis masalah ini.

Tapi ini mungkin pendekatan "paling buruk" untuk dipertimbangkan untuk sesuatu yang kecil.


sumber
Saya setuju dengan kamu. Masalah yang saya hadapi adalah bahwa saya ingin sepenuhnya menulis ulang perpustakaan untuk v2.0.0 (karena ada banyak masalah ini yang perlu diperbaiki); jadi saya tidak ingin perubahan sekecil iterator membentuk dasar dari perubahan besar ini. Jadi opsi saya adalah: abaikan bug ini, atau perbaiki bug dan masukkan ke versi utama baru?
hohner
@ hohner - jawaban yang diperbarui untuk memberikan pendekatan alternatif dengan membuat fungsi baru. Ingatlah bahwa banyak fungsi baru yang bernama hampir sama buruknya dengan mengubah API itu sendiri.
3
@ hohner: Secara konsisten salah> tidak benar dalam kasus ini. Perilaku itu masih berfungsi, hanya saja tidak idiomatis. Pertimbangkan bahwa jika Anda melakukan perubahan ini, Anda melanggar kode klien. Untuk melakukan ini tanpa peringatan tidak akan dihargai.
Phoshi
@ GlenH7 Dalam hal ini, menggunakan metode alternatif tidak akan berfungsi. Iterator asli PHP bergantung pada metode ini (yaitu next()tidak nextCorrect()). Saya akan melihat apakah saya dapat memodifikasi next () sehingga kompatibel mundur DAN berfungsi ketika mengimplementasikan Iteratorantarmuka.
hohner
1
@ Phoshi Anda tepat - saya sepenuhnya setuju sekarang. Sekarang saatnya untuk mencoba dan membuat kode yang mustahil: D
hohner