Saya mengubah satu tanda tangan metode dan sekarang memiliki lebih dari 25.000 kesalahan. Apa sekarang?

166

Saya memulai pekerjaan baru baru-baru ini di mana saya bekerja pada aplikasi yang sangat besar (15 juta loc). Dalam pekerjaan saya sebelumnya kami memiliki aplikasi yang sama besar tetapi (untuk lebih baik atau lebih buruk) kami menggunakan OSGi, yang berarti aplikasi tersebut dipecah menjadi banyak layanan Microsoft yang dapat diubah, dikompilasi, dan digunakan secara mandiri. Aplikasi baru ini hanya satu basis kode besar, mungkin dengan beberapa .dlls.

Jadi saya perlu mengubah antarmuka kelas ini, karena itulah yang diminta bos saya. Mereka awalnya menulisnya dengan beberapa asumsi yang tidak menggeneralisasi terlalu baik, dan untuk sementara waktu mereka menghindari masalah refactoring karena sangat erat. Saya mengubah antarmuka dan sekarang ada lebih dari 25.000 kesalahan. Beberapa kesalahan dalam kelas dengan nama terdengar penting seperti "XYZPriceCalculator" yang reaaallyseharusnya tidak pecah. Tetapi saya tidak dapat memulai aplikasi untuk memeriksa apakah itu berfungsi sampai semua kesalahan diselesaikan. Dan banyak dari unit test yang secara langsung merujuk antarmuka itu, atau digabungkan ke kelas dasar yang mereferensikan antarmuka itu, jadi hanya memperbaiki itu adalah tugas yang cukup besar dalam dirinya sendiri. Ditambah lagi, aku tidak benar-benar tahu bagaimana semua potongan ini cocok, jadi walaupun aku bisa memulainya, aku tidak benar-benar tahu seperti apa jadinya jika semuanya rusak.

Saya tidak pernah benar-benar menghadapi masalah seperti ini di pekerjaan terakhir saya. Apa yang saya lakukan?

pengguna788497
sumber
7
Anda perlu memberi kami informasi lebih lanjut tentang jenis kesalahan dan apa "kelas ini", kami bukan pembaca pikiran.
whatsisname
137
"lebih dari 25000 kesalahan" angka-angka seperti yang ditunjukkan dalam VS sering salah. Ada beberapa kesalahan, tetapi dengan membangun dll yang sering digunakan rusak, build lain gagal juga, sehingga meningkatkan angka kesalahan astronomi. Saya selalu mulai memperbaiki dengan pesan kesalahan pertama yang ditemukan di output build, bukan di daftar kesalahan.
Bernhard Hiller
13
Saya ingin melihat tanda tangan sebelum dan sesudah pada metode yang Anda ubah. BTW - 25k kesalahan tidak benar-benar terdengar seperti terlalu banyak untuk ditangani. Ya membosankan, menakutkan, ya, tidak terkendali, tidak.
jmoreno
46
Antarmuka publik adalah kontrak. Jangan melanggar kontrak seperti itu - buat yang baru.
Matius Baca
6
25000 kesalahan !? Houston, kita punya masalah. Jelas mengembalikan perubahan dan berbicara dengan manajer Anda, jelaskan kepadanya bahwa Anda mungkin harus membuat antarmuka baru sama sekali.
Code Whisperer

Jawaban:

349

25000 kesalahan pada dasarnya berarti "jangan sentuh itu". Ubah kembali. Buat kelas baru yang memiliki antarmuka yang diinginkan dan perlahan-lahan pindahkan konsumen kelas ke yang baru. Bergantung pada bahasanya, Anda dapat menandai kelas lama sebagai usang, yang dapat menyebabkan semua jenis peringatan kompiler, tetapi tidak akan benar-benar merusak bangunan Anda.

Sayangnya hal-hal ini terjadi di basis kode yang lebih lama. Tidak banyak yang bisa Anda lakukan kecuali perlahan-lahan membuat segalanya lebih baik. Saat Anda membuat kelas baru, pastikan Anda mengujinya dengan benar dan membuatnya menggunakan prinsip-prinsip SOLID sehingga mereka akan lebih mudah untuk berubah di masa depan.

Stephen
sumber
79
Itu tidak harus menjadi kelas baru . Bergantung pada bahasa dan keadaan, itu mungkin sebuah fungsi, antarmuka, sifat, dll.
Jan Hudec
33
Ini juga membantu jika antarmuka lama dapat diganti dengan pembungkus kompatibilitas di sekitar yang baru.
Jan Hudec
79
Kadang-kadang, 25000 kesalahan sebenarnya berarti Kami tidak pernah berani menyentuh itu, tapi sekarang setelah pendatang baru tiba, mari kita beri dia tugas membersihkan kandang-Augean.
mouviciel
13
@Dmi: Saya setuju, 1 perubahan dan kesalahan 25k kemungkinan besar berarti perubahan 2.5k paling banyak, dan saya tidak akan terkejut menemukan bahwa itu sekitar 250. Banyak pekerjaan yang baik, tetapi bisa dilakukan.
jmoreno
33
25.000 kesalahan itu semua bisa diperbaiki dengan satu perubahan. Jika saya memecah kelas dasar dari sebuah heirarki besar, setiap kelas turunan akan memuntahkan kesalahan tentang basis tidak valid, setiap penggunaan kelas-kelas itu akan memuntahkan kesalahan tentang kelas yang tidak ada, dll. Bayangkan itu adalah "getName", dan saya menambahkan sebuah argumen. Override dalam kelas implementasi "HasAName" sekarang tidak berfungsi (kesalahan), dan semua yang diwarisi darinya sekarang menghasilkan kesalahan (semua 1000 kelas), serta setiap kali saya membuat instance dari salah satu dari mereka (24x per kelas pada rata-rata). Cara mengatasinya adalah ... satu baris.
Yakk
80

Bagilah dan taklukkan dengan refactoring

Seringkali, memecah perubahan yang perlu Anda lakukan menjadi langkah-langkah kecil dapat membantu karena Anda kemudian dapat melakukan sebagian besar langkah-langkah kecil dengan cara yang tidak merusak perangkat lunak sama sekali. Alat refactoring banyak membantu dengan tugas-tugas seperti itu.

Membagi

Pertama, identifikasi perubahan sekecil mungkin (dalam hal perubahan logis, bukan dalam hal perubahan LoC) yang meringkaskan perubahan yang ingin Anda capai. Terutama cobalah untuk mengisolasi langkah-langkah yang refactor murni dan dapat dilakukan dengan alat.

Menaklukkan

Untuk kasus rumit seperti milik Anda, mungkin masuk akal untuk melakukan satu refactoring kecil pada satu waktu dan kemudian membiarkan masalahnya tetap ada, sehingga semua sistem integrasi berkelanjutan dapat memverifikasi perubahan, dan mungkin tim penguji juga melihatnya. Ini memvalidasi langkah yang Anda buat.

Untuk melakukan refactoring tertentu, Anda benar-benar memerlukan dukungan alat untuk kasus di mana Anda memiliki 25.000 situs panggilan metode yang ingin Anda ubah. Mungkin pencarian-dan-ganti bekerja juga, tetapi untuk kasus kritis seperti itu, saya akan takut karenanya.

Contoh

Di C #, misalnya, dimungkinkan untuk menggunakan Resharper untuk mengubah tanda tangan suatu metode. Jika perubahannya cukup sederhana, misalnya menambahkan parameter baru, maka Anda dapat menentukan nilai mana yang harus digunakan di situs panggilan yang seharusnya memiliki kesalahan kompilasi.

Anda kemudian pada basis kode bebas kesalahan segera dan dapat menjalankan semua tes unit, yang akan berlalu, karena itu hanya refactoring.

Setelah tanda tangan metode terlihat bagus, Anda bisa pergi dan mengganti nilai yang ditambahkan Resharper sebagai argumen ke parameter yang baru diperkenalkan. Ini bukan refactoring lagi, tetapi Anda memiliki basis kode bebas kesalahan dan dapat menjalankan tes setelah setiap baris yang Anda ubah.

Terkadang itu tidak berhasil

Ini adalah pendekatan yang sangat berguna untuk kasus-kasus seperti milik Anda, di mana Anda memiliki banyak situs panggilan. Dan Anda memiliki perangkat lunak yang berfungsi sekarang, jadi dimungkinkan untuk membuat langkah refactoring kecil untuk mengubah tanda tangan sedikit saja, lalu lakukan yang lain.

Sayangnya itu tidak akan berfungsi jika perubahan tandatangan terlalu kompleks dan tidak dapat dipecah menjadi perubahan yang lebih kecil. Tetapi ini jarang terjadi; membelah masalah menjadi masalah yang lebih kecil biasanya menunjukkan bahwa adalah mungkin.

theDmi
sumber
12
Ini. Refactor jika Anda dapat (dengan aman), jika tidak, Anda perlu migrasi yang tepat.
sleske
3
Dan untuk cinta apa pun, silakan gunakan alat refactoring bawaan IDE Anda, daripada hanya mengubah tanda tangan metode (misalnya) secara lokal dan kemudian memperbaiki kesalahan yang terjadi.
KlaymenDK
36

Perjelas tugas Anda dengan bos Anda untuk membantunya memahami masalah dan kebutuhan Anda sebagai pengembang perangkat lunak profesional.

Jika Anda adalah bagian dari tim, cari pengembang utama dan mintalah saran.

Semoga berhasil.

mmehl
sumber
15
Ini adalah langkah pertama yang saya ambil - "Saya seorang junior dan bos saya mengatakan kepada saya untuk melakukan sesuatu dan sekarang saya mendapatkan pesan kesalahan yang sangat besar, tetapi bos saya tidak memberi tahu saya tentang itu." Langkah 1: "Hei bos, saya melakukan hal itu, tetapi saya mendapatkan kesalahan 25k sekarang. Apakah itu seharusnya terjadi, atau ..."
Pimgd
28

Jangan menyentuhnya. Jangan melakukan apa pun.

Sebaliknya, duduklah di kursi Anda dan berteriak "Heeeeelp !!!!!" sekeras yang Anda bisa.

Ya, tidak persis seperti itu, tetapi mintalah saran dari kolega senior Anda. Jika Anda memiliki 25.000 kesalahan, Anda tidak memperbaiki kesalahan, Anda memperbaiki apa yang menyebabkan kesalahan. Dan seorang kolega senior harus bisa memberi tahu Anda cara melakukan perubahan yang diinginkan atasan Anda tanpa melibatkan 25.000 kesalahan. Ada berbagai cara untuk melakukan ini, tetapi cara yang baik tergantung pada situasi spesifik Anda.

Dan mungkin bos memberi tahu kolega senior Anda untuk melakukan perubahan yang sama, dan mereka berkata "tidak". Karena mereka tahu apa yang akan terjadi. Itu sebabnya kamu diberi pekerjaan.

gnasher729
sumber
2
Ini jelas merupakan hal penting yang perlu diingat. Jika seorang karyawan baru benar-benar ambisius untuk sebagian besar, mereka mungkin rajin (mudah tertipu) cukup untuk melakukan tugas yang sangat besar yang hanya pada akhirnya mendapatkan keuntungan memori 5 byte atau sedikit lebih logis untuk mengode ulang dan memelihara nanti.
The Great Duck
@TheGreatDuck: Katakan padaku Anda belum pernah melihat antarmuka yang digunakan di mana-mana dan salah di mana-mana. Saya yakin sudah.
Yosua
@ Yosua itu bahkan tidak relevan dengan apa yang saya katakan. Ada kalanya memperbaiki bug kecil tidak selalu ide paling cerdas yang berarti menulis ulang 10.000 baris kode. Sayangnya, seorang karyawan baru mungkin cukup mudah tertipu untuk menarik 10 orang semalam di luar pekerjaan menulis ulang kode itu untuk mengesankan bos mereka dan menyelesaikannya. Tentu, ini hal yang bagus untuk dilakukan, tetapi kadang-kadang cukup sudah cukup. Anda hanya harus menerima keberadaan bug itu.
The Great Duck
1
@Joshua btw, saya hanya bergabung dengan komunitas ini karena pertanyaan ini muncul di umpan pertanyaan populer saya. Saya tidak punya pengalaman dengan desain skala besar seperti ini. Saya hanya setuju dengan pandangan orang ini.
The Great Duck
22

API yang dimurnikan tidak bisa diubah begitu saja. Jika Anda benar - benar perlu mengubahnya, ambil dan / atau dokumentasikan mereka sebagai usang (dengan cara apa pun yang dibolehkan bahasa) dan dokumentasikan API mana yang harus digunakan sebagai gantinya. API lama kemudian dapat dihapus secara perlahan ... mungkin sangat lambat tergantung pada anggaran waktu Anda untuk refactoring.

Kevin Krumwiede
sumber
10

Evaluasi

Evaluasi apakah perubahan ini diperlukan, atau apakah Anda dapat menambahkan metode baru dan menghapus yang lain.

Meneruskan

Jika diperlukan perubahan; maka rencana migrasi diperlukan.

Langkah pertama adalah memperkenalkan metode baru dan meminta metode lama memijat argumennya sehingga dapat memanggil metode baru. Ini mungkin memerlukan pengodean keras beberapa hal; tidak apa-apa.

Ini adalah titik komit: periksa apakah semua tes lulus, komit, tekan.

Migrasi

Pekerjaan yang sibuk memigrasi semua penelepon dari metode lama ke yang baru. Syukurlah itu bisa dilakukan secara bertahap berkat forwarder.

Jadi silakan; jangan ragu untuk menggunakan alat untuk membantu ( sedmenjadi yang paling mendasar, ada yang lain).

Tandai metode lama sebagai usang (dengan sedikit beralih ke metode baru); itu akan membantu Anda mengetahui apakah Anda lupa sesuatu dan akan membantu jika rekan kerja memperkenalkan panggilan ke metode lama saat Anda sedang mengerjakan ini.

Ini adalah titik komit (atau mungkin beberapa titik komit): periksa apakah semua tes lulus, komit, dorong.

Menghapus

Setelah beberapa waktu berlalu (mungkin hanya dalam sehari), cukup hapus metode yang lama.

Matthieu M.
sumber
4
sedmungkin ide yang buruk ... Sesuatu yang benar-benar "memahami" bahasa dan tidak akan membuat perubahan drastis yang tidak diinginkan lebih baik.
wizzwizz4
1
@ wizzwizz4: Sayangnya, saya telah menemukan sangat sedikit alat yang benar-benar memahami bahasa dengan cukup baik untuk C ++; sebagian besar alat tampaknya melayani penggantian nama dan hanya itu. Memang, mengganti nama hanya panggilan metode yang tepat (dan tidak ada kelebihan atau tidak terkait tetapi disebut metode panggilan) sudah mengesankan, tapi itu tidak cukup untuk hal yang lebih rumit. Paling tidak, Anda akan membutuhkan kemampuan untuk (1) mengocok argumen, (2) menerapkan transformasi ke argumen yang diberikan (panggilan .c_str()misalnya) dan memperkenalkan argumen baru. sedagak berfungsi, kompiler menangkap masalah setelahnya.
Matthieu M.
1
sed(atau ed) dapat mencukupi untuk hal semacam ini - selama Anda benar-benar meninjau perbedaan sebelum Anda berkomitmen.
Toby Speight
Ini adalah TCRR dari html, ya? :)
Daniel Springer
8

Jika perubahan Anda ke tanda tangan metode hanyalah perubahan nama, solusi sederhana adalah dengan menggunakan alat untuk mengotomatiskan perubahan di 25.000 kelas yang merujuk metode tersebut.

Saya berasumsi bahwa Anda baru saja mengedit kode secara manual, yang memunculkan semua kesalahan. Saya juga menganggap Anda terbiasa dengan Java (melihat referensi Anda ke OSGi), jadi misalnya di Eclipse (saya tidak tahu lingkungan pemrograman mana yang Anda gunakan, tetapi lingkungan lain memiliki alat refactoring yang serupa) Anda dapat menggunakan "Refactoring -> Ubah nama" untuk memperbarui semua referensi ke metode, yang seharusnya membuat Anda tanpa kesalahan.

Jika Anda membuat perubahan lain pada tanda tangan metode daripada hanya mengganti nama (mengubah jumlah atau jenis parameter), Anda dapat menggunakan "Refactoring -> Ubah metode tanda tangan". Namun, kemungkinan Anda harus lebih berhati-hati seperti jawaban yang disarankan. Juga, terlepas dari jenis perubahan itu mungkin masih cukup tugas melakukan semua perubahan itu di basis kode sibuk.

MikkelRJ
sumber
2
OP secara khusus mengatakan OSGi berada di pekerjaan mereka sebelumnya, jadi itu tidak benar-benar relevan di sini.
CVn
3
@ MichaelKjörling Jika OP adalah seorang programmer Java dalam pekerjaan mereka sebelumnya, ada kemungkinan yang lebih baik daripada mereka adalah programmer Java dalam pekerjaan ini juga.
Kaya
@ MichaelKjörling Saya ingin memberikan rekomendasi konkret, menggunakan Eclipse untuk refactoring karena OP terbiasa dengan Java. Apakah OP sebenarnya menggunakan Java untuk proyek saat ini, saya kira, kurang penting, tetapi saya harus menjelaskan jawaban saya. Terima kasih.
MikkelRJ
6

Di sini kontribusiku.

Saya memulai pekerjaan baru baru-baru ini di mana saya mengerjakan aplikasi yang sangat besar (15 juta baris kode).

Anda mungkin tidak terbiasa dengan proyek dan "fitur-fiturnya". Sebelum mengetikkan satu baris kode, penting untuk mengenal proyek ini. Jadi, kembalikan perubahan Anda dan mulai dengan menganalisis kode . (Setidaknya yang terkena)

Memahami solusi yang ada memberi Anda perspektif yang lebih baik tentang ke mana Anda akan masuk. Kontekstualisasikan solusi dan kepentingannya.

Seperti yang ditunjukkan @Greg, Anda harus dapat menguji kode yang ada untuk memiliki referensi yang valid untuk dibandingkan dengan (uji regresi). Solusi Anda harus mampu menghasilkan hasil yang sama dari yang ada. Pada tahap ini, apakah Anda tidak peduli apakah hasilnya benar atau tidak . Tujuan pertama adalah untuk memperbaiki, bukan untuk memperbaiki bug. Jika solusi yang ada mengatakan "2 + 2 = 42", solusi Anda juga harus. Jika tidak ada pengecualian, Anda juga tidak boleh. Jika mengembalikan nol, Anda juga harus mengembalikan nol. Dan seterusnya. Jika tidak, Anda akan membahayakan 25k baris kode.

Ini demi kompatibilitas retro.

Mengapa? Karena saat ini, Ini adalah jaminan unik Anda untuk refactor yang sukses.

Dan banyak dari unit test yang secara langsung merujuk antarmuka itu, atau digabungkan ke kelas dasar yang mereferensikan antarmuka itu.

Sebuah cara untuk menjamin kompatibilitas retro sangat dibutuhkan untuk Anda. Jadi inilah tantangan pertama Anda. Pisahkan komponen untuk pengujian unit.

Perlu diingat bahwa 25k baris kode dibuat dengan asumsi hasil yang mungkin dari kode yang ada. Jika Anda tidak melanggar bagian kontrak ini, maka Anda setengah jalan menuju solusi akhir. Jika Anda melakukannya, yah: mungkin kekuatannya menyertai Anda

Setelah Anda merancang dan mengimplementasikan "kontrak" baru, ganti yang lama. Jatuhkan atau keluarkan.

Saya menyarankan untuk meninggalkan bug sendirian karena refactoring dan memperbaiki bug adalah tugas yang berbeda. Jika Anda mencoba untuk memajukan keduanya, Anda mungkin gagal pada keduanya. Anda mungkin berpikir Anda menemukan bug, namun, mereka bisa jadi "fitur". Jadi biarkan mereka sendiri (sebentar).

Bagi saya, 25k baris kode cukup masalah untuk membuat saya fokus hanya pada satu tugas.

Setelah tugas pertama Anda selesai. Paparkan bug / fitur itu kepada bos Anda.

Akhirnya, seperti yang dikatakan @Stephen:

Tidak banyak yang bisa Anda lakukan kecuali perlahan-lahan membuat segalanya lebih baik. Saat Anda membuat kelas baru, pastikan Anda mengujinya dengan benar dan membuatnya menggunakan prinsip-prinsip SOLID sehingga mereka akan lebih mudah untuk berubah di masa depan

Laiv
sumber
5

Menguji.

Semua orang merekomendasikan cara melakukan refactor sehingga dampaknya kecil. Tetapi dengan banyak kesalahan, bahkan jika Anda berhasil melakukan refactoring dengan hanya 10 baris kode (Anda mungkin bisa), maka Anda telah memengaruhi 25.000 aliran kode , bahkan jika Anda tidak perlu menulis ulang.

Jadi, hal selanjutnya yang harus dilakukan adalah memastikan suite uji regresi Anda lulus dengan warna cerah. Dan jika Anda tidak memilikinya, maka buatlah yang akan. Menambahkan rangkaian uji regresi komprehensif ke proyek monolitik Anda terdengar membosankan tetapi merupakan cara yang bagus untuk meningkatkan kepercayaan pada kandidat rilis, serta melepaskan mereka lebih cepat jika suite tersebut diotomatisasi dengan baik.

Greg
sumber