Jadi kita memiliki file sumber mainmodule.cpp yang besar (11.000 baris?) Dalam proyek kami dan setiap kali saya harus menyentuhnya saya merasa ngeri.
Karena file ini sangat sentral dan besar, ia terus mengumpulkan kode semakin banyak dan saya tidak bisa memikirkan cara yang baik untuk membuatnya benar-benar mulai menyusut.
File tersebut digunakan dan secara aktif diubah di beberapa (10) versi pemeliharaan produk kami sehingga sangat sulit untuk memperbaikinya. Jika saya "hanya" membaginya, katakan untuk permulaan, menjadi 3 file, maka menggabungkan kembali perubahan dari versi pemeliharaan akan menjadi mimpi buruk. Dan juga jika Anda membagi file dengan sejarah yang panjang dan kaya, melacak dan memeriksa perubahan lama dalam SCC
sejarah tiba-tiba menjadi jauh lebih sulit.
File pada dasarnya berisi "kelas utama" (pengiriman dan koordinasi pekerjaan internal utama) dari program kami, sehingga setiap kali fitur ditambahkan, itu juga mempengaruhi file ini dan setiap kali tumbuh. :-(
Apa yang akan kamu lakukan dalam situasi ini? Adakah gagasan tentang cara memindahkan fitur baru ke file sumber terpisah tanpa mengacaukan SCC
alur kerja?
(Catatan pada alat: Kami menggunakan C ++ dengan Visual Studio
; Kami menggunakan AccuRev
sebagai SCC
tapi saya pikir jenis SCC
tidak terlalu penting di sini; Kami menggunakan Araxis Merge
untuk melakukan perbandingan aktual dan penggabungan file)
sumber
Jawaban:
Temukan beberapa kode dalam file yang relatif stabil (tidak berubah cepat, dan tidak banyak berbeda antar cabang) dan dapat berdiri sebagai unit independen. Pindahkan ini ke file-nya sendiri, dan untuk itu ke kelasnya sendiri, di semua cabang. Karena stabil, ini tidak akan menyebabkan (banyak) gabungan "canggung" yang harus diterapkan ke file yang berbeda dari yang semula mereka buat, ketika Anda menggabungkan perubahan dari satu cabang ke yang lain. Ulang.
Temukan beberapa kode dalam file yang pada dasarnya hanya berlaku untuk sejumlah kecil cabang, dan bisa berdiri sendiri. Tidak masalah apakah itu berubah cepat atau tidak, karena jumlah cabang yang kecil. Pindahkan ini ke dalam kelas dan file sendiri. Ulang.
Jadi, kami telah menyingkirkan kode yang sama di mana-mana, dan kode yang khusus untuk cabang tertentu.
Ini memberi Anda inti kode yang dikelola dengan buruk - diperlukan di mana-mana, tetapi berbeda di setiap cabang (dan / atau berubah secara konstan sehingga beberapa cabang berjalan di belakang yang lain), namun dalam satu file Anda gagal mencoba menggabungkan antara cabang. Berhenti lakukan itu. Cabang file secara permanen , mungkin dengan mengganti nama di masing-masing cabang. Ini bukan "utama" lagi, ini "utama untuk konfigurasi X". OK, jadi Anda kehilangan kemampuan untuk menerapkan perubahan yang sama ke beberapa cabang dengan menggabungkan, tapi ini inti dari kode di mana penggabungan tidak bekerja dengan baik. Jika Anda harus mengelola penggabungan secara manual untuk menangani konflik, maka tidak ada salahnya untuk menerapkannya secara independen di setiap cabang.
Saya pikir Anda salah mengatakan bahwa jenis SCC tidak masalah, karena misalnya kemampuan penggabungan git mungkin lebih baik daripada alat penggabung yang Anda gunakan. Jadi masalah intinya, "penggabungan sulit" terjadi pada waktu yang berbeda untuk SCC yang berbeda. Namun, Anda tidak mungkin dapat mengubah SCC, jadi masalahnya mungkin tidak relevan.
sumber
Penggabungan tidak akan menjadi mimpi buruk besar seperti ketika Anda akan mendapatkan 30000 file LOC di masa depan. Begitu:
Jika Anda tidak bisa berhenti mengkode selama proses refactoring, Anda bisa membiarkan file besar ini untuk sementara waktu setidaknya tanpa menambahkan lebih banyak kode ke dalamnya: karena mengandung satu "kelas utama" Anda bisa mewarisi darinya dan tetap mewarisi kelas ( es) dengan fungsi kelebihan beban di beberapa file kecil dan dirancang dengan baik.
sumber
Bagi saya sepertinya Anda menghadapi sejumlah kode yang berbau di sini. Pertama-tama kelas utama tampaknya melanggar prinsip terbuka / tertutup . Itu juga terdengar seperti menangani terlalu banyak tanggung jawab . Karena ini saya akan menganggap kode lebih rapuh daripada yang seharusnya.
Meskipun saya dapat memahami kekhawatiran Anda tentang keterlacakan setelah refactoring, saya berharap bahwa kelas ini agak sulit untuk dipertahankan dan ditingkatkan dan bahwa setiap perubahan yang Anda lakukan cenderung menyebabkan efek samping. Saya akan berasumsi bahwa biaya ini lebih besar daripada biaya refactoring kelas.
Bagaimanapun, karena kode bau hanya akan semakin buruk dengan waktu, setidaknya pada suatu titik biaya ini akan lebih besar daripada biaya refactoring. Dari uraian Anda, saya akan berasumsi bahwa Anda telah melewati titik kritis.
Refactoring ini harus dilakukan dalam langkah-langkah kecil. Jika mungkin, tambahkan tes otomatis untuk memverifikasi perilaku saat ini sebelum refactoring apa pun. Kemudian pilih area kecil fungsionalitas terisolasi dan ekstrak ini sebagai tipe untuk mendelegasikan tanggung jawab.
Bagaimanapun, itu terdengar seperti proyek besar, semoga sukses :)
sumber
Satu-satunya solusi yang pernah saya bayangkan untuk masalah seperti ini adalah sebagai berikut. Keuntungan aktual dengan metode yang dijelaskan adalah progresivitas evolusi. Tidak ada revolusi di sini, jika tidak, Anda akan berada dalam masalah dengan sangat cepat.
Masukkan kelas cpp baru di atas kelas utama asli. Untuk saat ini, pada dasarnya akan mengarahkan semua panggilan ke kelas utama saat ini, tetapi bertujuan membuat API dari kelas baru ini sejelas dan sesingkat mungkin.
Setelah ini dilakukan, Anda mendapatkan kemungkinan untuk menambahkan fungsionalitas baru di kelas baru.
Adapun fungsi yang ada, Anda harus secara progresif memindahkan mereka di kelas baru karena mereka menjadi cukup stabil. Anda akan kehilangan bantuan SCC untuk bagian kode ini, tetapi tidak banyak yang bisa dilakukan mengenai hal itu. Pilih waktu yang tepat.
Saya tahu ini tidak sempurna, meskipun saya harap ini bisa membantu, dan prosesnya harus disesuaikan dengan kebutuhan Anda!
Informasi tambahan
Perhatikan bahwa Git adalah SCC yang dapat mengikuti potongan kode dari satu file ke file lainnya. Saya telah mendengar hal-hal baik tentang itu, sehingga dapat membantu saat Anda secara progresif memindahkan pekerjaan Anda.
Git dibangun di sekitar gagasan gumpalan yang, jika saya mengerti benar, mewakili potongan file kode. Pindahkan potongan-potongan ini di dalam berbagai file dan Git akan menemukannya, bahkan jika Anda memodifikasinya. Terlepas dari video dari Linus Torvalds yang disebutkan dalam komentar di bawah, saya belum dapat menemukan sesuatu yang jelas tentang ini.
sumber
Konfusius berkata: "langkah pertama untuk keluar dari lubang adalah berhenti menggali lubang."
sumber
Biarkan saya menebak: Sepuluh klien dengan set fitur yang berbeda dan manajer penjualan yang mempromosikan "penyesuaian"? Saya telah mengerjakan produk seperti itu sebelumnya. Kami pada dasarnya memiliki masalah yang sama.
Anda tahu bahwa memiliki file yang sangat besar adalah masalah, tetapi bahkan lebih banyak masalah adalah sepuluh versi yang harus Anda pertahankan. Itu banyak perawatan. SCC dapat membuatnya lebih mudah, tetapi tidak bisa memperbaikinya.
Sebelum Anda mencoba untuk memecah file menjadi beberapa bagian, Anda perlu membawa kesepuluh cabang kembali sinkron satu sama lain sehingga Anda dapat melihat dan membentuk semua kode sekaligus. Anda dapat melakukan ini satu cabang pada satu waktu, menguji kedua cabang terhadap file kode utama yang sama. Untuk menegakkan perilaku kustom, Anda dapat menggunakan #ifdef dan teman-teman, tetapi lebih baik sebisa mungkin menggunakan biasa jika / selain terhadap konstanta yang ditentukan. Dengan cara ini, kompiler Anda akan memverifikasi semua jenis dan kemungkinan besar menghilangkan kode objek "mati". (Anda mungkin ingin mematikan peringatan tentang kode mati.)
Setelah hanya ada satu versi file yang dibagikan secara implisit oleh semua cabang, maka agak mudah untuk memulai metode refactoring tradisional.
#Ifdefs terutama lebih baik untuk bagian-bagian di mana kode yang terpengaruh hanya masuk akal dalam konteks penyesuaian per-cabang lainnya. Orang mungkin berpendapat bahwa ini juga menghadirkan peluang untuk skema penggabungan cabang yang sama, tetapi jangan menjadi liar. Tolong, satu proyek kolosal sekaligus.
Dalam jangka pendek, file tersebut akan muncul untuk tumbuh. Ini bagus. Apa yang Anda lakukan adalah menyatukan berbagai hal yang perlu disatukan. Setelah itu, Anda akan mulai melihat area yang jelas sama tanpa memandang versi; ini dapat dibiarkan sendiri atau di refactored sesuka hati. Area lain jelas akan berbeda tergantung versi. Anda memiliki sejumlah opsi dalam hal ini. Salah satu metode adalah mendelegasikan perbedaan ke objek strategi per-versi. Lain adalah untuk mendapatkan versi klien dari kelas abstrak umum. Tetapi tidak satu pun dari transformasi ini dimungkinkan selama Anda memiliki sepuluh "tips" pengembangan di cabang yang berbeda.
sumber
Saya tidak tahu apakah ini menyelesaikan masalah Anda, tetapi yang saya kira ingin Anda lakukan adalah memigrasi konten file ke file yang lebih kecil yang tidak tergantung satu sama lain (disimpulkan). Apa yang saya dapatkan adalah bahwa Anda memiliki sekitar 10 versi berbeda dari perangkat lunak yang beredar dan Anda perlu mendukung semuanya tanpa mengacaukan semuanya.
Pertama-tama tidak ada cara yang mudah dan akan menyelesaikan sendiri dalam beberapa menit brainstorming. Semua fungsi yang ditautkan dalam file Anda semuanya vital untuk aplikasi Anda, dan hanya dengan memotongnya dan memindahkannya ke file lain tidak akan menyelamatkan masalah Anda.
Saya pikir Anda hanya memiliki opsi ini:
Jangan bermigrasi dan tetap dengan apa yang Anda miliki. Mungkin keluar dari pekerjaan Anda dan mulai mengerjakan perangkat lunak serius dengan desain yang bagus. Pemrograman ekstrem tidak selalu merupakan solusi terbaik jika Anda bekerja pada proyek lama dengan dana yang cukup untuk bertahan satu atau dua crash.
Buat tata letak bagaimana Anda ingin file Anda terlihat setelah itu terpecah. Buat file yang diperlukan dan integrasikan ke dalam aplikasi Anda. Ubah nama fungsi atau kelebihannya untuk mengambil parameter tambahan (mungkin hanya boolean sederhana?). Setelah Anda harus mengerjakan kode Anda, migrasikan fungsi-fungsi yang perlu Anda kerjakan ke file baru dan petakan panggilan fungsi dari fungsi-fungsi lama ke fungsi-fungsi baru. Anda harus tetap memiliki file utama Anda dengan cara ini, dan masih dapat melihat perubahan yang dibuat untuk itu, setelah itu datang ke fungsi tertentu Anda tahu persis kapan itu di-outsourcing dan seterusnya.
Cobalah meyakinkan rekan kerja Anda dengan kue yang bagus bahwa alur kerja berlebihan dan bahwa Anda perlu menulis ulang beberapa bagian aplikasi untuk melakukan bisnis yang serius.
sumber
Persisnya masalah ini ditangani di salah satu bab buku "Bekerja Efektif dengan Kode Warisan" ( http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052 ).
sumber
Saya pikir Anda akan lebih baik membuat satu set kelas perintah yang memetakan ke poin API dari mainmodule.cpp.
Setelah mereka berada di tempat, Anda perlu untuk memperbaiki basis kode yang ada untuk mengakses poin-poin API ini melalui kelas perintah, setelah selesai, Anda bebas untuk mengubah setiap implementasi perintah ke dalam struktur kelas baru.
Tentu saja, dengan satu kelas 11 KLOC kode di sana mungkin sangat berpasangan dan rapuh, tetapi membuat kelas perintah individu akan membantu lebih banyak daripada strategi proxy / fasad lainnya.
Saya tidak iri dengan tugas itu, tetapi seiring berjalannya waktu masalah ini hanya akan bertambah buruk jika tidak ditangani.
Memperbarui
Saya menyarankan bahwa pola Command lebih disukai daripada Facade.
Lebih baik menjaga / mengorganisasikan banyak kelas Komando yang berbeda melalui Fasad (relatif) monolitik. Memetakan satu fasad tunggal ke file 11 KLOC mungkin perlu dipecah menjadi beberapa grup yang berbeda.
Mengapa repot-repot mencoba mencari tahu kelompok-kelompok fasad ini? Dengan pola Command Anda akan dapat mengelompokkan dan mengatur kelas-kelas kecil ini secara organik, sehingga Anda memiliki lebih banyak fleksibilitas.
Tentu saja, kedua opsi lebih baik daripada 11 KLOC tunggal dan tumbuh, file.
sumber
Salah satu saran penting: Jangan gabungkan refactoring dan perbaikan bug. Yang Anda inginkan adalah Versi program Anda yang identik dengan versi sebelumnya, kecuali bahwa kode sumbernya berbeda.
Salah satu caranya adalah dengan mulai membagi fungsi / bagian paling tidak besar ke dalam file itu sendiri dan kemudian memasukkannya dengan header (sehingga mengubah main.cpp menjadi daftar #includes, yang mengeluarkan bau kode pada dirinya sendiri * Saya tidak a C ++ Guru), tapi setidaknya sekarang dibagi menjadi file).
Anda kemudian dapat mencoba mengalihkan semua rilis pemeliharaan ke main.cpp "baru" atau apa pun struktur Anda. Lagi: Tidak ada perubahan atau perbaikan bug lain karena melacak itu membingungkan sekali.
Hal lain: Sebanyak yang Anda inginkan membuat satu umpan besar pada refactoring semuanya sekaligus, Anda mungkin menggigit lebih dari yang Anda bisa mengunyah. Mungkin hanya memilih satu atau dua "bagian", memasukkannya ke dalam semua rilis, lalu menambahkan beberapa nilai lebih untuk pelanggan Anda (setelah semua, Refactoring tidak menambah nilai langsung sehingga itu adalah biaya yang harus dibenarkan) dan kemudian pilih yang lain satu atau dua bagian.
Jelas itu membutuhkan beberapa disiplin dalam tim untuk benar-benar menggunakan file split dan tidak hanya menambahkan hal-hal baru ke main.cpp sepanjang waktu, tetapi sekali lagi, mencoba melakukan satu refactor besar mungkin bukan tindakan terbaik.
sumber
Rofl, ini mengingatkan saya pada pekerjaan lama saya. Tampaknya, sebelum saya bergabung, semuanya ada di dalam satu file besar (juga C ++). Kemudian mereka telah membaginya (pada titik yang benar-benar acak menggunakan termasuk) menjadi sekitar tiga (file masih besar). Kualitas perangkat lunak ini, seperti yang Anda duga, mengerikan. Proyek ini mencapai sekitar 40k LOC. (hampir tidak berisi komentar tetapi BANYAK kode duplikat)
Pada akhirnya saya melakukan penulisan ulang proyek secara lengkap. Saya mulai dengan mengulangi bagian terburuk dari proyek dari awal. Tentu saja saya memikirkan kemungkinan (kecil) antarmuka antara bagian baru ini dan yang lainnya. Kemudian saya memasukkan bagian ini ke dalam proyek lama. Saya tidak memperbaiki kode lama untuk membuat antarmuka yang diperlukan, tetapi hanya menggantinya. Kemudian saya mengambil langkah-langkah kecil dari sana, menulis ulang kode lama.
Saya harus mengatakan bahwa ini memakan waktu sekitar setengah tahun dan tidak ada pengembangan basis kode lama di samping perbaikan bug selama waktu itu.
edit:
Ukurannya tetap di sekitar 40k LOC tetapi aplikasi baru berisi lebih banyak fitur dan mungkin lebih sedikit bug dalam versi awal daripada perangkat lunak yang berusia 8 tahun. Salah satu alasan penulisan ulang itu adalah karena kami membutuhkan fitur-fitur baru dan memperkenalkannya di dalam kode lama hampir tidak mungkin.
Perangkat lunak ini untuk sistem tertanam, printer label.
Poin lain yang harus saya tambahkan adalah bahwa dalam teori proyek tersebut adalah C ++. Tapi itu bukan OO sama sekali, bisa saja C. Versi baru berorientasi objek.
sumber
OK jadi untuk sebagian besar menulis ulang API kode produksi adalah ide yang buruk sebagai permulaan. Dua hal perlu terjadi.
Pertama, Anda harus membuat tim Anda memutuskan untuk melakukan pembekuan kode pada versi produksi file ini saat ini.
Dua, Anda perlu mengambil versi produksi ini dan membuat cabang yang mengelola build menggunakan arahan preprocessing untuk membagi file besar. Memisahkan kompilasi menggunakan arahan preprocessor JUST (#ifdefs, #includes, #endifs) lebih mudah daripada pengodean ulang API. Ini jelas lebih mudah untuk SLA Anda dan dukungan berkelanjutan.
Di sini Anda cukup memotong fungsi yang berhubungan dengan subsistem tertentu di dalam kelas dan meletakkannya di file say mainloop_foostuff.cpp dan memasukkannya ke mainloop.cpp di lokasi yang tepat.
ATAU
Cara yang lebih memakan waktu tetapi kuat adalah untuk merancang struktur dependensi internal dengan dua arah dalam bagaimana hal-hal dimasukkan. Ini akan memungkinkan Anda untuk membagi hal-hal dan masih mengurus co-dependensi. Perhatikan bahwa pendekatan ini membutuhkan pengkodean posisi dan oleh karena itu harus digabungkan dengan komentar yang sesuai.
Pendekatan ini akan mencakup komponen yang digunakan berdasarkan varian mana yang Anda kompilasi.
Struktur dasarnya adalah mainclass.cpp Anda akan menyertakan file baru bernama MainClassComponents.cpp setelah blok pernyataan seperti berikut:
Struktur utama file MainClassComponents.cpp akan ada di sana untuk menyelesaikan dependensi dalam sub komponen seperti ini:
Dan sekarang untuk setiap komponen Anda membuat file component_xx.cpp.
Tentu saja saya menggunakan angka tetapi Anda harus menggunakan sesuatu yang lebih logis berdasarkan kode Anda.
Menggunakan preprocessor memungkinkan Anda untuk membagi berbagai hal tanpa harus khawatir tentang perubahan API yang merupakan mimpi buruk dalam produksi.
Setelah produksi selesai, Anda dapat benar-benar mengerjakan desain ulang.
sumber
Yah saya mengerti rasa sakit Anda :) Saya sudah di beberapa proyek seperti itu juga dan itu tidak cantik. Tidak ada jawaban mudah untuk ini.
Salah satu pendekatan yang dapat bekerja untuk Anda adalah mulai menambahkan pelindung aman di semua fungsi, yaitu, memeriksa argumen, pra / pasca-kondisi dalam metode, lalu akhirnya menambahkan unit test semua untuk menangkap fungsionalitas sumber saat ini. Setelah Anda memiliki ini, Anda lebih siap untuk faktor ulang kode karena Anda akan memiliki pemberitahuan dan kesalahan muncul mengingatkan Anda jika Anda telah melupakan sesuatu.
Kadang-kadang meskipun ada kalanya refactoring hanya dapat membawa lebih banyak rasa sakit daripada manfaat. Maka mungkin lebih baik meninggalkan proyek asli dan dalam kondisi pemeliharaan semu dan mulai dari awal dan kemudian secara bertahap menambahkan fungsi dari beast.
sumber
Anda seharusnya tidak khawatir dengan mengurangi ukuran file, melainkan dengan mengurangi ukuran kelas. Turun ke hampir sama, tetapi membuat Anda melihat masalah dari sudut yang berbeda (seperti @Brian Rasmussen menyarankan , kelas Anda tampaknya harus banyak tanggung jawab).
sumber
Apa yang Anda miliki adalah contoh klasik antipattern desain yang dikenal yang disebut gumpalan . Luangkan waktu untuk membaca artikel yang saya tunjukkan di sini, dan mungkin Anda mungkin menemukan sesuatu yang bermanfaat. Selain itu, jika proyek ini sebesar yang terlihat, Anda harus mempertimbangkan beberapa desain untuk mencegah berkembangnya kode yang tidak dapat Anda kontrol.
sumber
Ini bukan jawaban untuk masalah besar, tetapi solusi teoretis untuk bagian spesifiknya:
Cari tahu di mana Anda ingin membagi file besar menjadi subfile. Masukkan komentar dalam beberapa format khusus di masing-masing poin tersebut.
Tulis skrip yang cukup sepele yang akan memecah file menjadi beberapa subfile pada saat itu. (Mungkin komentar khusus telah menyematkan nama file yang dapat digunakan skrip sebagai instruksi untuk membaginya.) Ini harus mempertahankan komentar sebagai bagian dari pemisahan.
Jalankan skrip. Hapus file asli.
Saat Anda perlu menggabungkan dari cabang, pertama buat ulang file besar dengan menggabungkan potongan-potongan kembali, lakukan penggabungan, lalu pisahkan kembali.
Juga, jika Anda ingin mempertahankan sejarah file SCC, saya berharap cara terbaik untuk melakukannya adalah dengan memberi tahu sistem kontrol sumber Anda bahwa masing-masing file part adalah salinan dari aslinya. Maka itu akan mempertahankan sejarah bagian yang disimpan dalam file itu, meskipun tentu saja itu juga akan mencatat bahwa sebagian besar "dihapus".
sumber
Salah satu cara untuk membaginya tanpa terlalu banyak bahaya adalah dengan melihat secara historis semua perubahan garis. Apakah ada fungsi tertentu yang lebih stabil daripada yang lain? Titik panas perubahan jika Anda mau.
Jika suatu baris belum diubah dalam beberapa tahun, Anda mungkin dapat memindahkannya ke file lain tanpa terlalu khawatir. Saya akan melihat sumber yang dianotasi dengan revisi terakhir yang menyentuh garis yang diberikan dan melihat apakah ada fungsi yang bisa Anda tarik.
sumber
Wow, kedengarannya bagus. Saya pikir menjelaskan kepada atasan Anda, bahwa Anda perlu banyak waktu untuk memperbaiki binatang itu patut dicoba. Jika dia tidak setuju, berhenti adalah pilihan.
Bagaimanapun, apa yang saya sarankan pada dasarnya adalah membuang semua implementasi dan mengelompokkannya kembali ke dalam modul-modul baru, sebut saja "layanan global". "Modul utama" hanya akan meneruskan ke layanan-layanan itu dan APA PUN kode baru yang Anda tulis akan menggunakannya alih-alih "Modul Utama". Ini harus layak dalam jumlah waktu yang wajar (karena sebagian besar menyalin dan menempel), Anda tidak melanggar kode yang ada dan Anda dapat melakukannya satu versi pemeliharaan pada suatu waktu. Dan jika Anda masih memiliki waktu tersisa, Anda dapat menggunakannya untuk mengembalikan semua modul yang tergantung lama untuk juga menggunakan layanan global.
sumber
Simpati saya - dalam pekerjaan saya sebelumnya saya menghadapi situasi yang sama dengan file yang beberapa kali lebih besar dari yang Anda harus berurusan dengan. Solusi adalah:
Kelas yang Anda bangun di langkah 3. iterasi kemungkinan akan tumbuh untuk menyerap lebih banyak kode yang sesuai dengan fungsi mereka yang baru-jelas.
Saya juga bisa menambahkan:
0: beli buku Michael Feathers tentang bekerja dengan kode warisan
Sayangnya jenis pekerjaan ini terlalu umum, tetapi pengalaman saya adalah bahwa ada nilai yang besar untuk dapat membuat kode kerja tetapi mengerikan semakin sedikit lebih mengerikan sambil tetap bekerja.
sumber
Pertimbangkan cara untuk menulis ulang seluruh aplikasi dengan cara yang lebih masuk akal. Mungkin menulis ulang sebagian kecil sebagai prototipe untuk melihat apakah ide Anda layak.
Jika Anda telah mengidentifikasi solusi yang bisa diterapkan, refactor aplikasi yang sesuai.
Jika semua upaya untuk menghasilkan arsitektur yang lebih rasional gagal, maka setidaknya Anda tahu solusinya mungkin dalam mendefinisikan ulang fungsi program.
sumber
0,05 eurocents saya:
Rancang ulang seluruh kekacauan, pilah menjadi beberapa subsistem dengan mempertimbangkan persyaratan teknis dan bisnis (= banyak trek perawatan paralel dengan basis kode yang berpotensi berbeda untuk masing-masingnya, jelas ada kebutuhan untuk modifikasi yang tinggi, dll.).
Ketika membelah menjadi subsistem, analisis tempat-tempat yang paling berubah dan pisahkan dari bagian-bagian yang tidak berubah. Ini akan menunjukkan kepada Anda titik masalah. Pisahkan bagian-bagian yang paling berubah ke modul mereka sendiri (misalnya dll) sedemikian rupa sehingga API modul dapat tetap utuh dan Anda tidak perlu merusak BC sepanjang waktu. Dengan cara ini Anda dapat menggunakan versi modul yang berbeda untuk cabang pemeliharaan yang berbeda, jika perlu, sementara inti tidak berubah.
Desain ulang kemungkinan akan perlu menjadi proyek yang terpisah, mencoba melakukannya untuk target yang bergerak tidak akan berhasil.
Adapun sejarah kode sumber, pendapat saya: lupakan untuk kode baru. Tetapi simpan sejarah di suatu tempat sehingga Anda dapat memeriksanya, jika perlu. Saya yakin Anda tidak akan membutuhkannya setelah awal.
Anda kemungkinan besar perlu mendapatkan dukungan manajemen untuk proyek ini. Anda dapat berdebat mungkin dengan waktu pengembangan yang lebih cepat, lebih sedikit bug, pemeliharaan lebih mudah dan kekacauan keseluruhan lebih sedikit. Sesuatu di sepanjang baris "Secara proaktif memungkinkan kelayakan masa depan dan pemeliharaan aset aset kritis kami" :)
Ini adalah cara saya mulai mengatasi masalah setidaknya.
sumber
Mulailah dengan menambahkan komentar. Dengan referensi ke tempat fungsi dipanggil dan jika Anda dapat memindahkan barang-barang. Ini bisa membuat segalanya bergerak. Anda benar-benar perlu menilai seberapa rapuh basis kode itu. Kemudian pindahkan bit fungsionalitas bersama secara bersamaan. Perubahan kecil pada suatu waktu.
sumber
Buku lain yang menurut Anda menarik / bermanfaat adalah Refactoring .
sumber
Sesuatu yang menurut saya berguna untuk dilakukan (dan saya melakukannya sekarang walaupun tidak pada skala yang Anda hadapi), adalah mengekstraksi metode sebagai kelas (metode objek refactoring). Metode yang berbeda di berbagai versi Anda akan menjadi kelas yang berbeda yang dapat disuntikkan ke pangkalan bersama untuk memberikan perilaku berbeda yang Anda butuhkan.
sumber
Saya menemukan kalimat ini menjadi bagian paling menarik dari posting Anda:
> File tersebut digunakan dan secara aktif diubah dalam beberapa (> 10) versi pemeliharaan produk kami dan jadi sangat sulit untuk memperbaikinya
Pertama, saya akan merekomendasikan agar Anda menggunakan sistem kontrol sumber untuk mengembangkan 10 + versi pemeliharaan yang mendukung percabangan.
Kedua, saya akan membuat sepuluh cabang (satu untuk masing-masing versi pemeliharaan Anda).
Saya bisa merasakan Anda merasa ngeri! Tetapi kontrol sumber Anda tidak berfungsi untuk situasi Anda karena kurangnya fitur, atau tidak digunakan dengan benar.
Sekarang ke cabang tempat Anda bekerja - refactor sesuai keinginan Anda, aman dengan pengetahuan bahwa Anda tidak akan mengecewakan sembilan cabang lainnya dari produk Anda.
Saya akan sedikit khawatir bahwa Anda memiliki begitu banyak fungsi () utama Anda.
Dalam setiap proyek yang saya tulis, saya akan menggunakan main () hanya melakukan inisialisasi objek inti - seperti objek simulasi atau aplikasi - kelas-kelas ini adalah tempat pekerjaan nyata harus dilanjutkan.
Saya juga akan menginisialisasi objek log aplikasi untuk digunakan secara global di seluruh program.
Akhirnya, pada intinya saya juga menambahkan kode deteksi kebocoran di blok preprosesor yang memastikan itu hanya diaktifkan di build DEBUG. Ini semua yang akan saya tambahkan ke main (). Main () harus pendek!
Itu kata kamu
> File pada dasarnya berisi "kelas utama" (pengiriman dan koordinasi pekerjaan internal utama) dari program kami
Kedengarannya seperti dua tugas ini dapat dibagi menjadi dua objek terpisah - koordinator dan dispatcher kerja.
Ketika Anda membagi ini, Anda mungkin mengacaukan "alur kerja SCC" Anda, tetapi kedengarannya seperti menempel ketat pada alur kerja SCC Anda menyebabkan masalah pemeliharaan perangkat lunak. Parit, sekarang dan jangan melihat ke belakang, karena begitu Anda memperbaikinya, Anda akan mulai mudah tidur.
Jika Anda tidak dapat mengambil keputusan, bertarunglah dengan manajer Anda untuk hal itu - aplikasi Anda perlu di refactored - dan sangat buruk oleh suara itu! Jangan menerima jawaban tidak!
sumber
Seperti yang telah Anda jelaskan, masalah utamanya adalah membedakan pre-split vs post-split, menggabungkan perbaikan bug dll. Alat di sekitarnya. Tidak perlu waktu lama untuk membuat hardcode pada skrip di Perl, Ruby, dll. Untuk merobek sebagian besar noise dari membedakan pre-split dengan gabungan post-split. Lakukan apa pun yang paling mudah dalam menangani kebisingan:
Anda bahkan dapat membuatnya jadi setiap kali ada checkin, rangkaiannya berjalan dan Anda punya sesuatu yang dipersiapkan untuk berbeda dengan versi file tunggal.
sumber
sumber
"File ini pada dasarnya berisi" kelas utama "(pengiriman dan koordinasi pekerjaan internal utama) dari program kami, jadi setiap kali fitur ditambahkan, itu juga memengaruhi file ini dan setiap kali tumbuh."
Jika itu SWITCH besar (yang saya pikir ada) menjadi masalah pemeliharaan utama, Anda bisa refactor untuk menggunakan kamus dan pola Command dan menghapus semua logika switch dari kode yang ada ke loader, yang mengisi peta itu, yaitu:
sumber
Saya pikir cara termudah untuk melacak riwayat sumber ketika memisahkan file adalah seperti ini:
sumber
Saya pikir apa yang akan saya lakukan dalam situasi ini adalah sedikit peluru dan:
Melacak perubahan lama ke file hanya diselesaikan dengan komentar check-in pertama Anda mengatakan sesuatu seperti "split from mainmodule.cpp". Jika Anda perlu kembali ke sesuatu yang baru, kebanyakan orang akan mengingat perubahan, jika 2 tahun dari sekarang, komentar akan memberi tahu mereka ke mana harus mencari. Tentu saja, betapa berharganya untuk kembali lebih dari 2 tahun untuk melihat siapa yang mengubah kode dan mengapa?
sumber