Bagaimana cara refactor ketika semua pengembangan Anda di cabang?

24

Di perusahaan saya, semua pengembangan kami (perbaikan bug dan fitur baru) dilakukan pada cabang terpisah. Ketika sudah selesai, kami mengirimkannya ke QA yang mengujinya di cabang itu, dan ketika mereka memberi kami lampu hijau, kami menggabungkannya ke cabang utama kami. Ini bisa memakan waktu antara hari dan tahun.

Jika kami mencoba memeras setiap refactoring ke dalam cabang, kami tidak tahu berapa lama akan "keluar", sehingga dapat menyebabkan banyak konflik saat digabungkan kembali.

Sebagai contoh, katakanlah saya ingin mengganti nama suatu fungsi karena fitur yang saya kerjakan sangat memanfaatkan fungsi ini, dan saya menemukan bahwa namanya tidak sesuai dengan tujuannya (sekali lagi, ini hanyalah sebuah contoh). Jadi saya berkeliling dan menemukan setiap penggunaan fungsi ini, dan mengubah nama mereka semua menjadi nama baru, dan semuanya berfungsi dengan baik, jadi saya mengirimkannya ke QA.

Sementara itu, pengembangan baru sedang terjadi, dan fungsi berganti nama saya tidak ada pada salah satu cabang yang sedang bercabang main. Ketika masalah saya digabungkan kembali, mereka semua akan rusak.

Apakah ada cara untuk mengatasi ini?

Ini tidak seperti manajemen akan pernah menyetujui masalah hanya refactor sehingga harus diperas dengan pekerjaan lain. Itu tidak dapat dikembangkan langsung pada main karena semua perubahan harus melalui QA dan tidak ada yang ingin menjadi brengsek yang memecahkan main sehingga ia bisa melakukan sedikit refactoring yang tidak penting.

Mpen
sumber
Apa kontrol versi yang Anda gunakan? Ada berbagai pendekatan untuk DVCS dan model server terpusat. Selain itu, cabang apa yang diambil dari cabang pengembangan? Jika cabang fitur diterima, bagaimana cabang dev lainnya menerima perubahan?
2
Sebagai tambahan, diagram struktur percabangan saat ini bisa sangat membantu. Sangat mungkin bahwa akar masalah dengan kesulitan dengan refactoring sebagian disebabkan oleh beberapa ... kebijakan percabangan yang tidak konvensional (lihat programmers.stackexchange.com/questions/210360 untuk satu contoh seperti itu). Saya juga menyarankan membaca vance.com/steve/perforce/Branching_Strategies.html untuk mendapatkan beberapa ide dan latar belakang (jika saya bisa menjawab pertanyaan ini yang akan menjadi titik referensi utama).
1
Paragraf terakhir merangkumnya - jika Bisnis tidak memahami nilainya, tidak mungkin refactor besar dapat melanjutkan. Anda perlu bekerja dengan tim pengujian Anda untuk menyelesaikan jadwal mereka. (Saya menduga QA Anda benar-benar Uji seret (Mereka mengenakan wig dan lipstik dan berpura-pura menjadi sesuatu yang bukan). Tim QA yang sesungguhnya akan memberi tahu Anda apa yang harus direfaktor, tidak menghalangi Anda.)
mattnz
1
@ mattnz: Anda benar. Mereka bukan tim QA yang nyata. Mereka kebanyakan adalah dukungan pelanggan. Saya pikir banyak tanggung jawab mereka harus dialihkan kembali ke tim Dev karena mereka tidak bisa menangani semua yang kita timbulkan pada mereka, tapi itu masalah manajemen dan perjuangan yang belum saya menangkan.
buka
3
Anda melewatkan penggalian saya. Tes! = QA. QA mengawasi kualitas, dan bertujuan untuk meningkatkan hasil bisnis. Uji coba untuk membuktikan tidak adanya cacat dengan menemukannya.
mattnz

Jawaban:

12

Ada beberapa masalah yang bercampur bersama untuk membuat refactoring menantang di lingkungan ini. Bercampur dengan ini adalah beberapa masalah non-teknis ("tapi itu masalah manajemen dan pertempuran yang belum saya menangkan").

Masalah pertama yang harus dilihat adalah cabang yang sudah berjalan lama. Cabang-cabang ini mengalami kesulitan melacak perubahan di luar tampilan pengembang. Untuk mengatasi ini:

  • Ketika kode selesai - berikan sekali lagi (biarkan dukungan pelanggan melihatnya jika mereka mau), tetapi gabungkan dengan cepat ke dalam pengembangan sehingga perubahan lain yang bergantung padanya akan dapat diambil dan perubahan yang konflik diidentifikasi lebih awal dalam proses.
  • Jika, karena suatu alasan suatu brach menjadi berjalan lama ketika refactoring sedang berlangsung, itu cenderung menjadi praktik yang baik untuk bergabung dari stabil ke cabang untuk mengambil perubahan dan refactoring. Seringkali ini meminimalkan konflik dan kejutan pada penggabungan dari cabang fitur ke cabang stabil.
  • Semua pengujian integrasi harus dilakukan pada rilis - bukan fitur . Dalam lingkungan ini fitur mungkin atau tidak sepenuhnya terintegrasi dengan sistem. Meskipun dimungkinkan untuk melakukan pemeriksaan kewarasan pada fitur secara terpisah, itu tidak mengidentifikasi masalah pada rilis.
  • Dari waktu penyelesaian kode untuk bergabung (sebut saja itu berkembang - bercabang dari master / stable / release memiliki masalah sendiri untuk tidak mengambil perubahan pengembangan terbaru) tidak boleh terlalu lama. Semakin lama Anda menunggu, semakin banyak pengetahuan yang hilang dan semakin sulit bagi kode untuk terintegrasi dengan baris kode lainnya.

Masalah lain yang mencampuradukkan hal ini adalah bahwa saya menyinggung poin-poin di atas adalah perubahan peran cabang dari waktu ke waktu. Ini dimulai sebagai cabang pengembangan di mana pengembang melakukan, dan kemudian menjadi area pengujian (pengujian apa yang sedang dilakukan di sini yang dapat bermakna di seluruh aplikasi?), Yang kemudian digabungkan menjadi stabil (dan mungkin dirilis - apakah itu diuji lagi?).

Dengan fitur yang lebih pendek, mulai dari waktu ke waktu, refactoring lebih mudah diambil oleh cabang lain.

Dorong pengembang untuk mendapatkan seluruh lingkungan. Hanya dengan memetik perubahan ceri dapat menyebabkan ... katakanlah lingkungan pengembang yang menarik. Sementara memetik ceri memiliki kegunaannya, untuk itu menjadi mode default dari menarik perubahan ke cabang bisa mengkhawatirkan.

Refactoring adalah sesuatu yang idealnya dilakukan terus-menerus, atau jika tidak terus-menerus setiap kali ada sedikit downtime. Cabang, lakukan refactoring sederhana, jalankan tes unit untuk memverifikasi semuanya masih berfungsi (unitnya diuji, kan? Benar? ) Dan kemudian bergabung kembali menjadi stabil. Sampaikan informasi untuk pengembang lain untuk menarik perubahan yang telah Anda refactored ke cabang mereka sendiri.

Penting bagi pengembang untuk memiliki kualitas kode. Meskipun arah fitur berasal dari luar, dan alokasi waktu seringkali bukan milik kita sendiri, kualitas kode adalah sesuatu yang perlu dibanggakan dan diluangkan waktu.

Anda mungkin menemukan pertanyaan-pertanyaan berikut berguna dalam pencarian untuk mengalokasikan waktu untuk berurusan dengan hutang teknis:

Anda mungkin juga ingin melihat alat-alat seperti sonar yang dapat membantu mengidentifikasi area kode yang paling membutuhkan pekerjaan untuk refactoring. The Plugin utang teknis adalah sesuatu yang dapat digunakan untuk membantu titik keluar akumulasi utang dari waktu ke waktu dalam basis kode.

Seringkali perlu untuk menunjukkan bahwa ROI untuk berurusan dengan utang teknis adalah waktu penyelesaian yang lebih cepat untuk fitur dan perbaikan bug dari tim pengembangan.

Komunitas
sumber
Tes pada dasarnya dilakukan pada tiga titik waktu. Sekali ketika masalah ini diklaim telah diperbaiki (untuk memastikan itu memenuhi semua persyaratan dan tidak ada masalah besar), sekali lagi ketika digabungkan kembali ke default (pengujian integrasi), dan sekali lagi ketika kita melakukan pembangunan (integrasi dengan semua cherry pick masalah / peninjauan akhir). Saya pikir memetik ceri diperlukan di lingkungan kita karena kita mengoperasikan SaaS dengan klien yang sangat khusus. Saya akan melihat tautan ini, terima kasih untuk petunjuknya! Sunting: Sebenarnya ada satu lagi pemeriksaan produksi untuk memastikan itu naik OK.
mpen
3

Biasanya saya mengembangkan versi refactored "paralel" dengan arus, yaitu dalam basis kode yang sama, tetapi tidak merujuknya dari aplikasi inti. Dan ketika solusi baru dilakukan dan diuji, saya memulai refactoring yang sebenarnya.

Contoh 1. Anggap saya memiliki benda, biarkan saja fungsi, antarmuka, modul, atau apa pun. Dan saya ingin memperbaikinya. Saya membuat Thing2 dalam basis kode yang sama, itu adalah versi refactored dari Thing. Ketika selesai dan diuji, saya refactoring semua yang mereferensikan Thing, untuk menggantinya dengan Thing2. Biasanya langkah ini membutuhkan waktu yang relatif sedikit.

Jika refactoring yang sebenarnya membutuhkan terlalu banyak waktu untuk tetap sinkron tanpa mengacaukan tim, saya mengambil semua fitur yang relevan, dan juga refactoring mereka secara paralel.

Contoh 2. Saya punya backend rendering baru, yaitu versi lama yang sudah di-refactored. Tapi itu tidak kompatibel dengan frontend rendering lama. Jadi, saya perlu memperbaiki frontend. Dan lagi: dalam basis kode yang sama. Ketika semuanya sudah selesai, saya hanya mengubah kelas instance frontend, idealnya akan membutuhkan satu komit pendek.

Ya, secara rekursif orang dapat menyimpulkan bahwa segala sesuatu harus dilakukan secara paralel. Tapi ini biasanya terjadi ketika ada terlalu banyak kopel dalam basis kode, atau itu berubah terlalu cepat.

Akhirnya, ketika kode baru terintegrasi dan berfungsi dengan baik, fitur lama dapat dihapus dari basis kode, dan fitur baru dapat diganti namanya untuk mendapatkan nama lama.

Secara umum, ide adalah untuk menyiapkan fitur-fitur baru secara paralel dan beralih untuk menggunakannya dengan satu langkah kecil.

John Carmack menggunakan pendekatan ini (atau paling tidak serupa), mungkin posting blognya menjelaskan lebih baik: (tautan)

Shadows In Rain
sumber
Ini pendekatan yang bagus. Saya mencoba mengingat apa yang sebenarnya mendorong pertanyaan ini sekarang ... Saya tidak berpikir itu adalah sesuatu yang sangat cocok untuk paralelisasi. Atau jika itu, saya pikir kekhawatiran saya adalah bahwa pendekatan ini menyebabkan banyak fragmentasi dalam basis kode. Kami memiliki "cara lama" dalam melakukan sesuatu dan "cara baru" dalam melakukan sesuatu, dan hal-hal lama sedang diganti dengan kecepatan tinggi, tetapi hal itu menyebabkan sakit kepala bagi para pengembang karena sekarang mereka pada dasarnya harus mengetahui dua (atau lebih) sistem.
mpen
1

Ini mungkin terlihat seperti kesulitan di sisi teknis ketika sebenarnya itu di sisi persyaratan.

Di mana pengembangan berorientasi pada persyaratan yang berbeda di cabang yang berbeda adalah kesulitan nyata. Manajer dan arsitek tim harus membuat keputusan yang dapat memungkinkan kebutuhan Bisnis yang berbeda untuk hidup berdampingan.

Proses ZBB dan Co-Dev "kompromi" ketika dilakukan setelah membuat keputusan yang tepat dengan input yang relevan dari semua pengembang, kata penutup memungkinkan Anda menerapkan apa yang Anda butuhkan tanpa harus berpikir - Bagaimana saya akan menggabungkan kode saya.

ZBB singkatan dari penganggaran berbasis Nol . Dengan mengatakan Co-Dev, saya bermaksud beberapa orang yang bekerja dalam pemrograman paralel.

Yosi Dahari
sumber
2
apa itu "ZBB" dan "Co-Dev"?
Agak
ZBB - en.wikipedia.org/wiki/Zero-based_budgeting . Dengan mengatakan Co-Dev, saya bermaksud beberapa orang yang bekerja dalam pemrograman paralel.
Yosi Dahari
1

Masalahnya bagi saya bahwa Anda bekerja terlalu lama di cabang. Biaya konflik tumbuh secara eksponensial dengan lamanya setiap orang menginap di cabang, jadi dengan konflik yang sangat lama Anda memiliki sedikit peluang untuk melakukan refactoring apa pun.

gnasher729
sumber
0

Masalah Anda adalah model cabang yang Anda gunakan. Anda bisa berkembang di cabang, dan ketika sudah selesai dan siap untuk QA, cabang akan digabung menjadi 'batang perantara', kadang-kadang disebut Integrasi atau Uji. Saat Anda mengembangkan fitur berikutnya, Anda dapat melakukan percabangan dari batang perantara ini sebagai gantinya.

Model ini memungkinkan Anda untuk mengembangkan beberapa fitur secara paralel pada cabang-cabang yang berbeda, menggabungkan semuanya bersama-sama ke cabang Integrasi untuk dikirim ke QA, dan juga mempertahankan satu batang rilis (Anda menggabungkan basis kode yang diterima QA ke bagasi utama ketika mereka mengesahkannya). )

Anda membuat asumsi bahwa perubahan Anda yang dikirimkan ke QA akan berlalu tanpa modifikasi besar sekalipun - jika kode QA kembali dengan instruksi untuk menghapus setengah dari perubahan, Anda harus mengembalikan tetapi jika itu tidak terjadi itu akan membuat perkembangan Anda jauh lebih lancar. Jadi Anda pada dasarnya mengambil cabang untuk fitur-fitur baru dari apa kode garis utama Anda nantinya (yaitu trunk setelah menggabungkan kode yang dilewatkan ke QA), daripada seperti sekarang ini (yaitu trunk saat ini) dan jadi tidak lagi berkembang terhadap basis kode rilis sebelumnya .

gbjbaanb
sumber