Apa cara terbaik untuk menangani refactoring file besar?

41

Saat ini saya sedang mengerjakan proyek yang lebih besar yang sayangnya memiliki beberapa file di mana pedoman kualitas perangkat lunak tidak selalu diikuti. Ini termasuk file besar (baca 2000-4000 baris) yang jelas mengandung banyak fungsi berbeda.

Sekarang saya ingin memperbaiki file besar ini menjadi beberapa file kecil. Masalahnya adalah, karena mereka sangat besar, banyak orang (termasuk saya) di cabang yang berbeda sedang mengerjakan file-file ini. Jadi saya tidak bisa benar-benar bercabang dari pengembangan dan refactor, karena menggabungkan refactoring ini dengan perubahan orang lain akan menjadi sulit.

Kami tentu saja dapat meminta semua orang untuk bergabung kembali untuk mengembangkan, "membekukan" file (yaitu tidak mengizinkan siapa pun untuk mengeditnya lagi), refactor, dan kemudian "unfreeze". Tapi ini juga tidak terlalu bagus, karena ini akan mengharuskan semua orang untuk menghentikan pekerjaan mereka pada file-file ini sampai refactoring selesai.

Jadi apakah ada cara untuk refactor, tidak mengharuskan orang lain untuk berhenti bekerja (terlalu lama) atau menggabungkan kembali cabang fitur mereka untuk dikembangkan?

Hoff
sumber
6
Saya pikir ini juga tergantung pada bahasa pemrograman yang digunakan.
Robert Andrzantai
8
Saya suka checkin "incremental kecil". Kecuali jika seseorang tidak menyimpan salinan repo mereka, praktik ini akan meminimalkan konflik penggabungan untuk semua orang.
Matt Raffel
5
Seperti apa tes Anda? Jika Anda akan melakukan refactor pada kode yang besar (dan mungkin penting!), Pastikan test suite Anda dalam kondisi sangat baik sebelum Anda melakukan refactor. Ini akan membuatnya jauh lebih mudah untuk memastikan Anda melakukannya dengan benar di file yang lebih kecil.
corsiKa
1
Ada banyak pendekatan yang bisa Anda ambil dengan ini dan pendekatan terbaik akan tergantung pada situasi Anda.
Stephen
3
Saya bergabung dengan proyek di mana file terbesar adalah 10k baris panjang yang berisi antara lain kelas yang panjangnya 6k baris dan semua orang takut untuk menyentuhnya. Maksud saya, pertanyaan Anda bagus. Kami bahkan menemukan lelucon bahwa kelas tunggal ini adalah alasan yang bagus untuk membuka kunci roda gulir di mouse kami.
ElmoVanKielmo

Jawaban:

41

Anda telah memahami dengan benar bahwa ini bukan masalah teknis melainkan masalah sosial: jika Anda ingin menghindari konflik penggabungan yang berlebihan, tim perlu berkolaborasi dengan cara yang menghindari konflik ini.

Ini adalah bagian dari masalah yang lebih besar dengan Git, karena percabangan itu sangat mudah tetapi penggabungan masih membutuhkan banyak usaha. Tim pengembang cenderung meluncurkan banyak cabang dan kemudian terkejut bahwa menggabungkan mereka sulit, mungkin karena mereka berusaha meniru Git Flow tanpa memahami konteksnya.

Aturan umum untuk menggabungkan cepat dan mudah adalah untuk mencegah perbedaan besar dari akumulasi, khususnya bahwa cabang fitur harus sangat singkat (jam atau hari, bukan bulan). Tim pengembang yang dapat dengan cepat mengintegrasikan perubahan mereka akan melihat lebih sedikit konflik yang menggabungkan. Jika beberapa kode belum siap diproduksi, dimungkinkan untuk mengintegrasikannya tetapi menonaktifkannya melalui flag fitur. Segera setelah kode tersebut diintegrasikan ke dalam cabang utama Anda, kode tersebut dapat diakses oleh jenis refactoring yang Anda coba lakukan.

Itu mungkin terlalu banyak untuk masalah langsung Anda. Tetapi mungkin layak untuk meminta kolega untuk menggabungkan perubahan mereka yang berdampak pada file ini sampai akhir minggu sehingga Anda dapat melakukan refactoring. Jika mereka menunggu lebih lama, mereka harus berurusan dengan konflik gabungan sendiri. Itu bukan tidak mungkin, itu hanya pekerjaan yang bisa dihindari.

Anda mungkin juga ingin mencegah kerusakan petak besar kode dependen dan hanya membuat perubahan yang kompatibel dengan API. Misalnya, jika Anda ingin mengekstrak beberapa fungsionalitas ke modul terpisah:

  1. Ekstrak fungsionalitas ke dalam modul terpisah.
  2. Ubah fungsi lama untuk meneruskan panggilan mereka ke API baru.
  3. Seiring waktu, kode dependen port ke API baru.
  4. Akhirnya, Anda dapat menghapus fungsi-fungsi lama.
  5. (Ulangi untuk banyak fungsi berikutnya)

Proses multi-langkah ini dapat menghindari banyak menggabungkan konflik. Secara khusus, hanya akan ada konflik jika orang lain juga mengubah fungsionalitas yang Anda ekstrak. Biaya pendekatan ini adalah jauh lebih lambat daripada mengubah semuanya sekaligus, dan untuk sementara Anda memiliki dua API duplikat. Ini tidak terlalu buruk sampai sesuatu yang mendesak mengganggu refactoring ini, duplikasinya dilupakan atau diprioritaskan, dan Anda berakhir dengan banyak utang teknologi.

Tetapi pada akhirnya, solusi apa pun akan mengharuskan Anda untuk berkoordinasi dengan tim Anda.

amon
sumber
1
@Laiv Sayangnya itu semua adalah saran yang sangat umum, tetapi beberapa ide keluar dari ruang lincah seperti Integrasi Berkelanjutan jelas memiliki kelebihan mereka. Tim yang bekerja bersama (dan mengintegrasikan pekerjaan mereka sering) akan memiliki waktu yang lebih mudah untuk membuat perubahan lintas sektoral yang besar daripada tim yang hanya bekerja berdampingan. Ini belum tentu tentang SDLC pada umumnya, lebih lanjut tentang kolaborasi dalam tim. Beberapa pendekatan membuat bekerja bersama lebih layak (pikirkan Prinsip Terbuka / Tertutup, layanan mikro) tetapi tim OP belum ada di sana.
amon
22
Saya tidak akan mengatakan lebih jauh bahwa cabang fitur perlu memiliki masa hidup yang singkat - hanya saja itu tidak boleh menyimpang dari cabang induknya untuk jangka waktu yang lama. Secara teratur menggabungkan perubahan dari cabang induk ke cabang fitur berfungsi dalam kasus-kasus di mana cabang fitur perlu bertahan lebih lama. Namun, ide yang bagus untuk menjaga cabang fitur tidak lebih dari yang diperlukan.
Dan Lyons
1
@Laiv Dalam pengalaman saya, masuk akal untuk mendiskusikan desain pasca-refaktor dengan tim sebelumnya, tetapi biasanya paling mudah jika satu orang membuat perubahan pada kode. Jika tidak, Anda kembali ke masalah yang harus Anda gabungkan. Garis 4k terdengar sangat banyak, tetapi sebenarnya tidak untuk refactor yang ditargetkan seperti ekstrak-kelas . (Saya akan penjudi buku Refactoring Martin Fowler begitu keras di sini jika saya telah membacanya.) Tapi 4k garis adalah banyak hanya untuk ditargetkan refactorings seperti “mari kita lihat bagaimana saya bisa memperbaiki ini”.
amon
1
@DanLyons Pada prinsipnya Anda benar: itu dapat menyebar beberapa upaya penggabungan. Dalam praktiknya, penggabungan Git sangat tergantung pada komitmen leluhur umum terbaru dari cabang yang digabung. Menggabungkan master → fitur tidak memberi kita nenek moyang yang sama pada master, tetapi menggabungkan fitur → master tidak. Dengan penggabungan fitur master → berulang, dapat terjadi bahwa kita harus menyelesaikan konflik yang sama berulang kali (tetapi lihat git rerere untuk mengotomatisasi ini). Rebasing benar-benar unggul di sini karena ujung master menjadi leluhur bersama yang baru, tetapi penulisan ulang sejarah memiliki masalah lain.
amon
1
Jawabannya OK untuk saya kecuali kata-kata kasar tentang git membuatnya terlalu mudah untuk bercabang, dan dengan demikian devs cabang terlalu sering. Saya ingat betul saat-saat SVN dan bahkan CVS ketika percabangan cukup sulit (atau paling tidak rumit) sehingga orang umumnya menghindarinya jika memungkinkan, dengan semua masalah terkait. Dalam git, sebagai sistem terdistribusi , memiliki banyak cabang benar-benar tidak ada bedanya dengan memiliki banyak repositori yang terpisah sama sekali (yaitu, pada setiap dev). Solusinya ada di tempat lain, mudah bercabang bukan masalah. (Dan ya, saya memang melihat bahwa itu hanya samping ... tapi tetap saja).
AnoE
30

Lakukan refactoring dalam langkah-langkah kecil. Katakanlah file besar Anda memiliki nama Foo:

  1. Tambahkan file kosong baru Bar,, dan komit ke "trunk".

  2. Temukan sebagian kecil dari kode Fooyang dapat dipindahkan Bar. Terapkan langkah tersebut, perbarui dari trunk, bangun dan uji kode, dan komit ke "trunk".

  3. Ulangi langkah 2 hingga Foodan Barmemiliki ukuran yang sama (atau ukuran apa pun yang Anda inginkan)

Dengan begitu, lain kali rekan tim Anda memperbarui cabang mereka dari trunk, mereka mendapatkan perubahan Anda dalam "porsi kecil" dan dapat menggabungkan mereka satu per satu, yang jauh lebih mudah daripada harus menggabungkan pemisahan penuh dalam satu langkah. Hal yang sama berlaku ketika pada langkah 2 Anda mendapatkan konflik gabungan karena orang lain memperbarui trunk di antaranya.

Ini tidak akan menghilangkan konflik gabungan atau kebutuhan untuk menyelesaikannya secara manual, tetapi membatasi setiap konflik ke area kode yang kecil, yang jauh lebih mudah dikelola.

Dan tentu saja - komunikasikan refactoring dalam tim. Beri tahu teman Anda apa yang Anda lakukan, sehingga mereka tahu mengapa mereka harus mengharapkan konflik gabungan untuk file tertentu.

Doc Brown
sumber
2
Ini sangat berguna dengan rerereopsi
git
@ D.BenKnoble: terima kasih untuk penambahan itu. Saya harus mengakui, saya bukan ahli git (tapi masalah yang dijelaskan tidak khusus untuk git, itu berlaku untuk VCS mana pun yang memungkinkan percabangan, dan jawaban saya harus sesuai dengan sebagian besar sistem itu).
Doc Brown
Saya pikir berdasarkan terminologi; pada kenyataannya, dengan git, penggabungan semacam ini masih dilakukan hanya sekali (jika seseorang hanya menarik dan menggabungkan). Tetapi seseorang dapat selalu menarik dan memilih, atau menggabungkan komitmen individu, atau rebase tergantung pada preferensi dev. Dibutuhkan lebih banyak waktu tetapi tentu bisa dilakukan jika penggabungan otomatis sepertinya gagal.
D. Ben Knoble
18

Anda berpikir untuk memisahkan file sebagai operasi atom, tetapi ada beberapa perubahan menengah yang dapat Anda lakukan. File berangsur-angsur menjadi besar dari waktu ke waktu, secara bertahap dapat menjadi kecil dari waktu ke waktu.

Pilih bagian yang tidak harus berubah dalam waktu lama ( git blamedapat membantu dengan ini), dan pisahkan dulu. Dapatkan perubahan itu digabung menjadi cabang semua orang, lalu pilih bagian termudah berikutnya untuk dibagi. Mungkin memisahkan satu bagian saja merupakan langkah yang terlalu besar dan Anda hanya perlu melakukan pengaturan ulang di dalam file besar terlebih dahulu.

Jika orang tidak sering bergabung kembali untuk berkembang, Anda harus mendorong itu, kemudian setelah mereka bergabung, ambil kesempatan itu untuk memisahkan bagian-bagian yang baru saja mereka ubah. Atau minta mereka untuk melakukan pemisahan itu sebagai bagian dari tinjauan permintaan tarik.

Idenya adalah untuk perlahan-lahan bergerak ke arah tujuan Anda. Ini akan terasa seperti kemajuan lambat, tetapi kemudian tiba-tiba Anda akan menyadari kode Anda jauh lebih baik. Butuh waktu lama untuk mengubah kapal laut.

Karl Bielefeldt
sumber
File mungkin sudah mulai besar. File yang ukurannya dapat dibuat dengan cepat. Saya tahu orang yang bisa menulis 1000's LoC dalam satu hari atau minggu. Dan OP tidak menyebutkan tes otomatis, yang menunjukkan kepada saya bahwa mereka kurang.
ChuckCottrill
9

Saya akan menyarankan solusi yang berbeda dari biasanya untuk masalah ini.

Gunakan ini sebagai acara kode tim. Mintalah semua orang memeriksa kode mereka yang dapat, kemudian bantu orang lain yang masih bekerja dengan file tersebut. Setelah semua orang yang relevan memiliki kode mereka masuk, cari ruang konferensi dengan proyektor dan bekerja bersama untuk mulai memindahkan berbagai hal ke dalam dan ke file baru.

Anda mungkin ingin menetapkan jumlah waktu tertentu untuk ini, sehingga tidak berakhir menjadi argumen bernilai satu minggu tanpa akhir yang terlihat. Sebaliknya, ini bahkan bisa menjadi acara 1-2 jam setiap minggu sampai Anda semua mendapatkan hal-hal yang terlihat seperti seharusnya. Mungkin Anda hanya perlu 1-2 jam untuk memperbaiki file. Anda tidak akan tahu sampai Anda mencoba, mungkin.

Ini bermanfaat bagi semua orang yang berada di halaman yang sama (tidak ada permainan kata-kata yang dimaksudkan) dengan refactoring, tetapi juga dapat membantu Anda menghindari kesalahan serta mendapatkan masukan dari orang lain tentang kemungkinan pengelompokan metode yang perlu dipertahankan, jika perlu.

Melakukannya dengan cara ini dapat dianggap memiliki tinjauan kode bawaan, jika Anda melakukan hal semacam itu. Ini memungkinkan jumlah dev yang sesuai untuk keluar dari kode Anda segera setelah Anda memeriksanya dan siap untuk ditinjau. Anda mungkin masih ingin mereka memeriksa kode untuk apa pun yang Anda lewatkan, tetapi perlu waktu lama untuk memastikan proses peninjauan lebih pendek.

Ini mungkin tidak berfungsi di semua situasi, tim, atau perusahaan, karena pekerjaan tidak didistribusikan dengan cara yang membuat ini terjadi dengan mudah. Ini juga dapat (salah) ditafsirkan sebagai penyalahgunaan waktu dev. Kode grup ini memerlukan dukungan dari manajer dan juga refactor itu sendiri.

Untuk membantu menjual ide ini kepada manajer Anda, sebutkan bit ulasan kode serta semua orang tahu di mana letak semuanya dari awal. Mencegah para dev dari kehilangan waktu mencari sejumlah file baru bisa bermanfaat untuk dihindari. Juga, mencegah para dev mendapatkan POed tentang di mana segalanya berakhir atau "benar-benar hilang" biasanya merupakan hal yang baik. (Semakin sedikit krisis semakin baik, IMO.)

Setelah Anda mendapatkan satu file yang dire-refoured dengan cara ini, Anda mungkin dapat dengan lebih mudah mendapatkan persetujuan untuk lebih banyak refaktor, jika itu berhasil dan bermanfaat.

Namun Anda memutuskan untuk melakukan refactor Anda, semoga berhasil!

biaya komputer
sumber
Ini adalah saran fantastis yang menangkap cara yang sangat baik untuk mencapai koordinasi tim yang akan menjadi penting untuk membuatnya bekerja. Selain itu, jika beberapa cabang tidak dapat digabungkan kembali ke yang masterpertama, Anda setidaknya memiliki semua orang di ruangan itu untuk membantu menangani penggabungan ke cabang-cabang itu.
Colin Young
+1 untuk menyarankan gerombolan kode
Jon Raynor
1
Ini persis membahas aspek sosial dari masalah.
ChuckCottrill
4

Memperbaiki masalah ini memerlukan dukungan dari tim lain karena Anda mencoba mengubah sumber daya bersama (kode itu sendiri). Yang sedang berkata, saya pikir ada cara untuk "bermigrasi" dari memiliki file monolitik besar tanpa mengganggu orang.

Saya juga merekomendasikan untuk tidak menargetkan semua file besar sekaligus kecuali jika jumlah file besar bertambah tak terkendali di samping ukuran file individual.

Refactoring file besar seperti ini sering menyebabkan masalah yang tidak terduga. Langkah pertama adalah menghentikan file-file besar dari mengumpulkan fungsi tambahan di luar apa yang saat ini di master atau di cabang pengembangan .

Saya pikir cara terbaik untuk melakukan ini adalah dengan kait komit yang memblokir tambahan tertentu ke file besar secara default, tetapi dapat ditolak dengan komentar ajaib dalam pesan komit, seperti @bigfileokatau sesuatu. Sangat penting untuk dapat mengesampingkan kebijakan dengan cara yang tidak menyakitkan tetapi dapat dilacak. Idealnya, Anda harus mampu menjalankan komit hook lokal dan harus memberitahu Anda bagaimana untuk menimpa kesalahan tertentu dalam pesan kesalahan itu sendiri . Juga, ini hanya preferensi saya, tetapi komentar magis yang tidak dikenal atau komentar magis yang menekan kesalahan yang tidak benar-benar aktif dalam pesan komit harus menjadi peringatan atau kesalahan komit waktu sehingga Anda tidak secara tidak sengaja melatih orang untuk menekan kait terlepas dari apakah mereka perlu atau tidak.

Hook komit dapat memeriksa kelas baru atau melakukan analisis statis lainnya (ad hoc atau tidak). Anda juga dapat memilih jumlah baris atau karakter yang 10% lebih besar dari file saat ini dan mengatakan bahwa file besar tidak dapat tumbuh melampaui batas baru. Anda juga dapat menolak komitmen individual yang menumbuhkan file besar dengan terlalu banyak baris atau terlalu banyak karakter atau w / e.

Setelah file besar berhenti mengumpulkan fungsionalitas baru, Anda dapat melakukan refactor hal-hal satu per satu (dan mengurangi tresholds yang dipaksakan oleh kait komit pada saat yang sama untuk mencegahnya tumbuh lagi).

Akhirnya, file-file besar akan cukup kecil sehingga kait komit dapat sepenuhnya dihapus.

Gregory Nisbet
sumber
-3

Tunggu hingga tiba waktunya. Pisahkan file, komit dan gabung untuk dikuasai.

Orang lain harus menarik perubahan ke cabang fitur mereka di pagi hari seperti perubahan lainnya.

Ewan
sumber
3
Tetap berarti mereka harus menggabungkan refactoring saya dengan perubahan mereka ...
Hoff
1
Yah, mereka sebenarnya harus berurusan dengan penggabungan bagaimanapun juga jika mereka semua mengubah file-file ini.
Laiv
9
Ini memiliki masalah "Kejutan, aku menghancurkan semua barangmu." OP perlu mendapatkan persetujuan dan persetujuan sebelum melakukan ini, dan melakukannya pada waktu yang dijadwalkan sehingga tidak ada orang lain yang memiliki file "dalam proses" akan membantu.
computercarguy
6
Untuk cinta cthulhu, jangan lakukan ini. Ini tentang cara terburuk Anda dapat bekerja dalam tim.
Lightness Races dengan Monica