Saya bekerja pada basis kode yang agak besar. Ratusan kelas, berton-ton file berbeda, banyak fungsionalitas, membutuhkan lebih dari 15 menit untuk menarik salinan baru, dll.
Masalah besar dengan basis kode yang besar adalah ia memiliki beberapa metode utilitas dan melakukan hal yang sama, atau memiliki kode yang tidak menggunakan metode utilitas ini ketika bisa. Dan juga metode utilitas tidak hanya semua dalam satu kelas (karena itu akan menjadi berantakan campur aduk besar).
Saya agak baru dalam basis kode, tetapi pemimpin tim yang telah mengerjakannya selama bertahun-tahun tampaknya memiliki masalah yang sama. Ini mengarah ke banyak kode dan duplikasi kerja, dan dengan demikian, ketika sesuatu rusak, biasanya rusak dalam 4 salinan pada dasarnya kode yang sama
Bagaimana kita bisa mengekang pola ini? Seperti kebanyakan proyek besar, tidak semua kode didokumentasikan (meskipun ada beberapa) dan tidak semua kode ... baik, bersih. Tetapi pada dasarnya, akan sangat menyenangkan jika kita dapat bekerja untuk meningkatkan kualitas dalam hal ini sehingga di masa depan kita memiliki lebih sedikit duplikasi kode, dan hal-hal seperti fungsi utilitas lebih mudah ditemukan.
Juga, fungsi utilitas biasanya baik di beberapa kelas pembantu statis, di beberapa kelas pembantu non-statis yang bekerja pada objek tunggal, atau merupakan metode statis pada kelas yang terutama "membantu" dengan.
Saya punya satu percobaan dalam menambahkan fungsi utilitas sebagai metode Extension (saya tidak perlu internal kelas, dan itu pasti hanya diperlukan dalam skenario yang sangat spesifik). Ini memiliki efek mencegah mengacaukan kelas utama dan semacamnya, tetapi itu tidak benar-benar dapat ditemukan kecuali Anda sudah mengetahuinya
Jawaban:
Jawaban sederhananya adalah Anda benar-benar tidak dapat mencegah duplikasi kode. Namun Anda dapat "memperbaikinya" melalui proses penambahan berulang yang sulit dan berkesinambungan yang bermuara menjadi dua langkah:
Langkah 1. Mulai menulis tes pada kode lawas (lebih disukai menggunakan kerangka pengujian)
Langkah 2. Tulis ulang / refactor kode yang digandakan menggunakan apa yang telah Anda pelajari dari tes
Anda dapat menggunakan alat analisis statis untuk mendeteksi kode duplikat dan untuk C # ada banyak alat yang dapat melakukan ini untuk Anda:
Alat seperti ini akan membantu Anda menemukan poin dalam kode yang melakukan hal serupa. Lanjutkan menulis tes untuk menentukan apakah itu benar-benar dilakukan; gunakan tes yang sama untuk membuat kode duplikat lebih mudah digunakan. "Refactoring" ini dapat dilakukan dengan berbagai cara dan Anda dapat menggunakan daftar ini untuk menentukan yang benar:
Selain itu ada juga buku lengkap tentang topik ini oleh Michael C. Feathers, Bekerja Efektif dengan Legacy Code . Secara mendalam strategi yang berbeda dapat Anda ambil untuk mengubah kode menjadi lebih baik. Dia memiliki "algoritma perubahan kode warisan" yang tidak jauh dari proses dua langkah di atas:
Buku ini adalah bacaan yang baik jika Anda berurusan dengan pengembangan brown-field, yaitu kode lawas yang perlu diubah.
Pada kasus ini
Dalam kasus OP, saya dapat membayangkan kode yang tidak dapat diuji disebabkan oleh pot madu untuk "metode dan trik utilitas" yang mengambil beberapa bentuk:
Perhatikan bahwa tidak ada yang salah dengan ini, tetapi di sisi lain mereka biasanya sulit dipertahankan dan diubah. Metode ekstensi dalam. NET adalah metode statis, tetapi juga relatif mudah untuk diuji.
Sebelum Anda melanjutkan dengan refactorings, bicarakan dengan tim Anda tentang hal itu. Mereka harus disimpan pada halaman yang sama dengan Anda sebelum Anda melanjutkan dengan apa pun. Ini karena jika Anda refactoring sesuatu maka kemungkinan besar Anda akan menyebabkan konflik penggabungan. Jadi sebelum mengerjakan ulang sesuatu, selidiki, beri tahu tim Anda untuk mengerjakan poin kode tersebut dengan hati-hati sampai Anda selesai.
Karena OP baru mengenal kode tersebut, ada beberapa hal lain yang harus dilakukan sebelum Anda harus melakukan apa pun:
Semoga berhasil!
sumber
Kita juga bisa mencoba melihat masalahnya dari sudut lain. Alih-alih berpikir bahwa masalahnya adalah duplikasi kode, kami dapat mempertimbangkan jika masalahnya berasal dari kurangnya kebijakan untuk penggunaan kembali kode.
Baru-baru ini saya membaca buku Rekayasa Perangkat Lunak dengan Komponen yang Dapat Digunakan Kembali dan memang memiliki serangkaian ide yang sangat menarik tentang cara menumbuhkan penggunaan kembali kode di tingkat organisasi.
Penulis buku ini, Johannes Sametinger, menjelaskan sekumpulan hambatan untuk penggunaan kembali kode, beberapa secara konsep beberapa teknis. Contohnya:
Menurut penulis, tingkat reusabilitas yang berbeda terjadi tergantung pada kematangan organisasi.
Jadi, mungkin, di samping semua saran yang diberikan dalam jawaban lain, Anda dapat bekerja pada merancang program reusability, melibatkan manajemen, membentuk grup komponen yang bertanggung jawab untuk mengidentifikasi komponen yang dapat digunakan kembali dengan melakukan analisis domain dan menentukan repositori komponen yang dapat digunakan kembali yang dapat dengan mudah dikembangkan oleh pengembang lain. permintaan dan cari solusi matang untuk masalah mereka.
sumber
Ada 2 solusi yang mungkin:
Pencegahan - Cobalah untuk memiliki dokumentasi sebaik mungkin. Jadikan setiap fungsi didokumentasikan dengan baik dan mudah dicari melalui seluruh dokumentasi. Juga, saat menulis kode, jelaskan ke mana kode harus pergi, jadi jelas ke mana harus mencari. Membatasi jumlah kode "utilitas" adalah salah satu poin utama dari ini. Setiap kali saya mendengar "mari membuat kelas utilitas", rambut saya naik dan darah saya membeku, karena itu jelas merupakan masalah. Selalu punya cara cepat dan mudah untuk meminta orang mengetahui basis kode setiap kali beberapa fitur sudah ada.
Solusi - Jika pencegahan gagal, Anda harus dapat dengan cepat dan efisien menyelesaikan potongan kode yang bermasalah. Proses pengembangan Anda harus memungkinkan untuk memperbaiki kode duplikat dengan cepat. Pengujian unit sangat cocok untuk ini, karena Anda dapat memodifikasi kode secara efisien tanpa takut merusaknya. Jadi jika Anda menemukan 2 keping kode yang serupa, mengabstraksikannya menjadi suatu fungsi atau kelas harus mudah dengan sedikit refactoring.
Saya pribadi tidak berpikir pencegahan itu mungkin. Semakin Anda mencoba, semakin bermasalah untuk menemukan fitur yang sudah ada.
sumber
Saya tidak berpikir masalah semacam ini memiliki solusi umum. Kode duplikat tidak akan dibuat jika pengembang memiliki cukup kesediaan untuk mencari kode yang ada. Pengembang juga dapat memperbaiki masalah di tempat jika mereka mau.
Jika bahasanya C / C ++ penggabungan duplikasi akan lebih mudah karena fleksibilitas menghubungkan (orang dapat memanggil
extern
fungsi apa pun tanpa informasi sebelumnya). Untuk Java atau .NET, Anda mungkin perlu membuat kelas pembantu dan / atau komponen utilitas.Saya biasanya mulai menghapus duplikasi kode yang ada hanya jika kesalahan utama muncul dari bagian yang digandakan.
sumber
Ini adalah masalah khas dari proyek yang lebih besar yang telah ditangani oleh banyak programmer, yang telah memberikan kontribusi di bawah banyak tekanan teman sebaya. Sangat menggoda untuk membuat salinan kelas dan menyesuaikannya dengan kelas tertentu. Namun, ketika masalah ditemukan di kelas asal, itu juga harus dipecahkan dalam dekritnya yang sering dilupakan.
Ada solusi untuk ini dan itu disebut Generics yang telah diperkenalkan di Java 6. Ini adalah setara dengan C ++ yang disebut Template. Kode yang kelas pastinya belum diketahui dalam Kelas Generik. Silakan periksa Java Generics dan Anda akan menemukan berton-ton dokumentasi untuknya.
Pendekatan yang baik adalah menulis ulang kode yang tampaknya akan disalin / ditempel di banyak tempat dengan menulis ulang yang pertama yang perlu Anda perbaiki yaitu karena bug tertentu. Tulis ulang untuk menggunakan Generics dan juga menulis kode pengujian yang sangat ketat.
Pastikan bahwa setiap metode dari kelas Generik dipanggil. Anda juga dapat memperkenalkan alat cakupan kode: kode generik harus sepenuhnya mencakup kode karena akan digunakan di beberapa tempat.
Juga menulis kode pengujian yaitu menggunakan JUnit atau serupa untuk kelas yang ditunjuk pertama yang akan digunakan bersama dengan potongan kode Generik.
Mulai gunakan kode Generik untuk versi yang disalin kedua (sebagian besar kali) ketika semua kode sebelumnya bekerja dan sepenuhnya diuji. Anda akan melihat bahwa ada beberapa baris kode yang spesifik untuk Kelas yang ditunjuk. Anda dapat memanggil baris-baris kode ini dalam metode yang dilindungi abstrak yang perlu diimplementasikan oleh kelas turunan yang menggunakan kelas dasar Generic.
Ya itu adalah pekerjaan yang membosankan, tetapi saat Anda melanjutkannya akan lebih baik dan lebih baik untuk merobek kelas yang sama dan menggantinya dengan sesuatu yang sangat sangat bersih, ditulis dengan baik dan jauh lebih mudah untuk dipertahankan.
Saya memiliki situasi yang serupa di mana pada kelas generik akhirnya menggantikan sesuatu seperti 6 atau 7 kelas hampir identik lainnya yang semuanya hampir identik tetapi telah disalin dan ditempelkan oleh berbagai programmer selama periode waktu.
Dan ya, saya sangat mendukung pengujian kode secara otomatis. Ini akan lebih mahal di awal tetapi pasti akan menghemat banyak waktu secara keseluruhan. Dan cobalah untuk mencapai cakupan kode secara keseluruhan minimal 80% dan 100% untuk kode Generik.
Semoga ini bisa membantu dan semoga sukses.
sumber
Saya benar-benar akan menggemakan pendapat yang paling tidak populer di sini dan memihak
Gangnus
dan menyarankan bahwa duplikasi kode tidak selalu berbahaya dan kadang-kadang bisa menjadi kejahatan yang lebih rendah.Jika, katakanlah, Anda memberi saya opsi untuk menggunakan:
A) Pustaka gambar yang stabil (tidak berubah) dan kecil, telah teruji dengan baik , yang menduplikasi beberapa lusin baris kode matematika sepele untuk vektor matematika seperti produk titik dan lerps dan klem, tetapi sepenuhnya dipisahkan dari hal lain dan dibangun di sebagian kecil dari Sebentar.
B) perpustakaan gambar tidak stabil (cepat berubah) yang bergantung pada perpustakaan matematika epik untuk menghindari beberapa lusin baris kode yang disebutkan di atas, dengan perpustakaan matematika menjadi tidak stabil dan terus-menerus menerima pembaruan dan perubahan baru, dan oleh karena itu perpustakaan gambar juga harus dibangun kembali jika tidak langsung berubah juga. Dibutuhkan 15 menit untuk membersihkan semuanya.
... maka jelas itu harus menjadi no-brainer bagi kebanyakan orang bahwa A, dan sebenarnya justru karena duplikasi kode minor, lebih disukai. Penekanan utama yang perlu saya buat adalah bagian yang telah teruji dengan baik . Jelas tidak ada yang lebih buruk daripada memiliki kode duplikat yang bahkan tidak berfungsi sejak awal, pada saat itu duplikat bug.
Tetapi ada juga kopling dan stabilitas untuk dipikirkan, dan beberapa duplikasi sederhana di sana-sini dapat berfungsi sebagai mekanisme decoupling yang juga meningkatkan stabilitas (sifat tidak berubah) dari paket.
Jadi saran saya sebenarnya adalah untuk lebih fokus pada pengujian dan mencoba menemukan sesuatu yang benar-benar stabil (seperti tidak berubah, menemukan beberapa alasan untuk berubah di masa depan) dan dapat diandalkan yang ketergantungannya pada sumber luar, jika ada, adalah sangat stabil, lebih dari mencoba untuk menghapus semua bentuk duplikasi dalam basis kode Anda. Dalam lingkungan tim yang besar, yang terakhir cenderung menjadi tujuan yang tidak praktis, belum lagi bahwa itu dapat meningkatkan kopling dan jumlah kode tidak stabil yang Anda miliki di basis kode Anda.
sumber
Jangan lupa bahwa duplikasi kode tidak selalu berbahaya. Bayangkan: sekarang Anda memiliki beberapa tugas yang harus diselesaikan dalam modul proyek yang benar-benar berbeda. Sekarang ini adalah tugas yang sama.
Mungkin ada tiga alasan untuk itu:
Beberapa tema seputar tugas ini sama untuk kedua modul. Dalam hal ini duplikasi kode buruk dan harus dilikuidasi. Akan pintar untuk membuat kelas atau modul untuk mendukung tema ini dan menggunakan metode di kedua modul.
Tugas ini bersifat teoritis dalam hal proyek Anda. Misalnya, dari fisika atau matematika, dll. Tugas ada secara mandiri di proyek Anda. Dalam hal ini duplikasi kode buruk dan harus dilikuidasi juga. Saya akan membuat kelas khusus untuk fungsi tersebut. Dan gunakan fungsi tersebut di modul mana pun di mana Anda membutuhkannya.
Tetapi dalam kasus lain, kebetulan tugas adalah kebetulan sementara dan tidak lebih. Akan berbahaya untuk percaya bahwa tugas-tugas ini akan tetap sama selama perubahan proyek karena refactoring dan bahkan debugging. Dalam hal ini akan lebih baik untuk membuat dua fungsi / potongan kode yang sama di tempat yang berbeda. Dan perubahan di masa depan pada salah satu dari mereka tidak akan menyentuh yang lain.
Dan kasus ke-3 ini sangat sering terjadi. Jika Anda menduplikasi "tanpa sadar", sebagian besar karena alasan ini - itu bukan duplikasi nyata!
Jadi, cobalah untuk tetap bersih ketika itu benar-benar diperlukan dan jangan takut duplikasi jika bukan keharusan.
sumber
code duplication is not always harmful
adalah salah satu saran yang buruk.