Ada file sumber dalam proyek yang agak besar dengan beberapa fungsi yang sangat sensitif terhadap kinerja (disebut jutaan kali per detik). Bahkan, pengelola sebelumnya memutuskan untuk menulis 12 salinan fungsi yang masing-masing sangat sedikit berbeda, untuk menghemat waktu yang akan dihabiskan memeriksa persyaratan dalam satu fungsi.
Sayangnya, ini berarti kode tersebut adalah PITA untuk dipelihara. Saya ingin menghapus semua kode duplikat dan menulis hanya satu templat. Namun, bahasanya, Java, tidak mendukung templat, dan saya tidak yakin obat generik cocok untuk ini.
Rencana saya saat ini adalah menulis file yang menghasilkan 12 salinan fungsi (sebuah expander template sekali pakai saja, secara praktis). Saya tentu saja akan memberikan penjelasan berlebihan mengapa file harus dibuat secara programatis.
Kekhawatiran saya adalah bahwa ini akan menyebabkan kebingungan pengelola di masa depan, dan mungkin memperkenalkan bug yang tidak menyenangkan jika mereka lupa membuat ulang file setelah memodifikasinya, atau (bahkan lebih buruk) jika mereka memodifikasi file yang dihasilkan secara program. Sayangnya, singkat menulis ulang semuanya dalam C ++, saya tidak melihat cara untuk memperbaikinya.
Apakah manfaat dari pendekatan ini lebih besar daripada kerugiannya? Haruskah saya sebaliknya:
- Ambil pukulan kinerja dan gunakan fungsi tunggal yang dapat dipelihara.
- Tambahkan penjelasan mengapa fungsi tersebut harus digandakan 12 kali, dan anggun ambil beban pemeliharaan.
- Coba gunakan obat generik sebagai templat (mungkin tidak berfungsi seperti itu).
- Berteriaklah pada pengelola lama untuk membuat kode sehingga kinerja bergantung pada satu fungsi.
- Metode lain untuk mempertahankan kinerja dan rawatan?
PS Karena desain proyek yang buruk, membuat profil fungsi agak rumit ... namun, mantan pengelola telah meyakinkan saya bahwa kinerja yang dicapai tidak dapat diterima. Saya berasumsi dengan ini yang ia maksudkan lebih dari 5%, meskipun itu adalah tebakan lengkap dari saya.
Mungkin saya harus menguraikan sedikit. 12 salinan melakukan tugas yang sangat mirip, tetapi memiliki perbedaan kecil. Perbedaannya ada di berbagai tempat di seluruh fungsi, jadi sayangnya ada banyak, banyak, pernyataan bersyarat. Ada secara efektif 6 "mode" operasi, dan 2 "paradigma" operasi (kata-kata dibuat sendiri). Untuk menggunakan fungsi, seseorang menentukan "mode" dan "paradigma" operasi. Ini tidak pernah dinamis; setiap potongan kode menggunakan tepat satu mode dan paradigma. Semua 12 pasangan mode-paradigma digunakan di suatu tempat dalam aplikasi. Fungsi-fungsi tersebut dengan tepat dinamakan func1 to func12, dengan bilangan genap yang merepresentasikan paradigma kedua dan angka ganjil mewakili paradigma pertama.
Saya sadar bahwa ini adalah desain terburuk yang pernah ada jika perawatan adalah tujuannya. Tapi sepertinya "cukup cepat", dan kode ini tidak memerlukan perubahan untuk sementara waktu ... Juga perlu dicatat bahwa fungsi aslinya belum dihapus (meskipun kode mati sejauh yang saya tahu) , jadi refactoring akan menjadi sederhana.
sumber
Makefile
" (atau sistem apa pun yang Anda gunakan) dan hapus kompilasi setelah selesai selesai . Dengan cara ini mereka tidak memiliki kesempatan untuk memodifikasi file sumber yang salah.Jawaban:
Ini adalah situasi yang sangat buruk, Anda perlu refactor ini secepatnya - ini adalah utang teknis di itu terburuk - Anda bahkan tidak tahu betapa pentingnya kode benar-benar adalah - hanya berspekulasi bahwa itu penting.
Adapun solusi ASAP:
Sesuatu yang dapat dilakukan adalah menambahkan langkah kompilasi kustom. Jika Anda menggunakan Maven yang sebenarnya cukup sederhana untuk dilakukan, sistem build otomatis lainnya juga mungkin bisa mengatasinya. Tulis file dengan ekstensi berbeda dari .java dan tambahkan langkah kustom yang mencari sumber Anda untuk file seperti itu dan meregenerasi .java yang sebenarnya. Anda mungkin juga ingin menambahkan sangkalan besar pada file yang dibuat secara otomatis yang menjelaskan untuk tidak memodifikasinya.
Pro vs menggunakan file yang dibuat sekali saja: Pengembang Anda tidak akan mendapatkan perubahannya agar .java berfungsi. Jika mereka benar-benar menjalankan kode pada mesin mereka sebelum melakukan mereka akan menemukan bahwa perubahan mereka tidak berpengaruh (hah). Dan mungkin mereka akan membaca disclaimer. Anda benar-benar benar karena tidak mempercayai rekan setim dan masa depan Anda dengan mengingat bahwa file khusus ini harus diubah dengan cara yang berbeda. Ini juga memungkinkan pengujian otomatis, karena JUnit akan mengkompilasi program Anda sebelum menjalankan tes (dan membuat ulang file juga)
EDIT
Menilai dari komentar jawabannya muncul seolah-olah ini adalah cara untuk membuat pekerjaan ini tanpa batas dan mungkin OK untuk digunakan ke bagian penting kinerja lainnya dari proyek Anda.
Sederhananya: tidak.
Beban ekstra untuk menciptakan bahasa mini Anda sendiri, menulis generator kode untuk itu dan memeliharanya, belum lagi mengajarkannya kepada pengelola masa depan adalah neraka dalam jangka panjang. Di atas hanya memungkinkan cara yang lebih aman untuk menangani masalah saat Anda bekerja pada solusi jangka panjang . Apa yang akan dilakukan adalah di atas saya.
sumber
ant clean
atau apa pun yang setara dengan Anda. Tidak perlu meletakkan disclaimer di file yang bahkan tidak ada!Apakah pemeliharaannya nyata, atau hanya mengganggu Anda? Jika itu hanya mengganggu Anda, biarkan saja.
Apakah masalah kinerja itu nyata, atau apakah pengembang sebelumnya hanya berpikiran seperti itu? Masalah kinerja, lebih sering daripada tidak, tidak sesuai dengan yang diduga, bahkan ketika profiler digunakan. (Saya menggunakan teknik ini untuk menemukan mereka dengan andal.)
Jadi ada kemungkinan bahwa Anda memiliki solusi jelek untuk non-masalah, tetapi juga bisa menjadi solusi jelek untuk masalah nyata. Jika ragu, tinggalkan saja.
sumber
Benar-benar memastikan daripada di bawah nyata, produksi, kondisi (konsumsi memori realistis, yang memicu Pengumpulan Sampah secara realistis, dll), semua metode terpisah tersebut benar-benar membuat perbedaan kinerja (bukan hanya memiliki satu metode). Ini akan memakan waktu beberapa hari dari waktu Anda, tetapi dapat menghemat berminggu-minggu dengan menyederhanakan kode tempat Anda bekerja mulai sekarang.
Juga, jika Anda melakukan menemukan bahwa Anda membutuhkan semua fungsi, Anda mungkin ingin menggunakan Javassist untuk menghasilkan kode programatik. Seperti yang telah ditunjukkan oleh orang lain, Anda dapat mengotomatiskannya dengan Maven .
sumber
Mengapa tidak menyertakan semacam templat preprocessor \ pembuatan kode untuk sistem ini? Langkah build tambahan khusus yang mengeksekusi dan memancarkan file sumber java tambahan sebelum mengkompilasi sisa kode. Ini adalah cara memasukkan klien web dari file wsdl dan xsd sering bekerja.
Anda tentu saja akan memiliki pemeliharaan generator kode preprocessor \ itu, tetapi Anda tidak perlu khawatir tentang pemeliharaan kode inti duplikat.
Karena waktu kompilasi kode Java sedang dipancarkan, tidak ada penalti kinerja yang harus dibayar untuk kode tambahan. Tetapi Anda mendapatkan penyederhanaan pemeliharaan dengan memiliki templat alih-alih semua kode yang digandakan.
Java generics tidak memberikan manfaat kinerja karena jenis penghapusan dalam bahasa, casting sederhana digunakan sebagai gantinya.
Dari pemahaman saya tentang template C ++, mereka dikompilasi menjadi beberapa fungsi per setiap permintaan template. Anda akan berakhir dengan kode waktu kompilasi tengah duplikat untuk setiap jenis yang Anda simpan di std :: vector misalnya.
sumber
Tidak ada metode Java waras yang cukup panjang untuk memiliki 12 varian ... dan JITC membenci metode yang panjang - hanya menolak untuk mengoptimalkannya dengan benar. Saya telah melihat faktor percepatan dua dengan hanya membagi metode menjadi dua yang lebih pendek. Mungkin ini jalan yang harus ditempuh.
OTOH yang memiliki banyak salinan mungkin masuk akal bahkan jika ada yang identik. Karena masing-masing digunakan di tempat yang berbeda, mereka dioptimalkan untuk kasus yang berbeda (JITC profil mereka dan kemudian menempatkan kasus langka di jalur yang luar biasa.
Saya akan mengatakan bahwa menghasilkan kode bukanlah masalah besar, dengan asumsi ada alasan bagus. Biaya overhead agak rendah, dan file yang dinamai dengan benar akan langsung mengarah ke sumbernya. Beberapa waktu yang lalu ketika saya menghasilkan kode sumber, saya meletakkan
// DO NOT EDIT
di setiap baris ... Saya kira itu cukup menghemat.sumber
Sama sekali tidak ada yang salah dengan 'masalah' yang Anda sebutkan. Dari apa yang saya tahu ini adalah jenis desain dan pendekatan yang tepat digunakan oleh server DB untuk memiliki kinerja yang baik.
Mereka memiliki banyak metode khusus untuk memastikan mereka dapat memaksimalkan kinerja untuk semua jenis operasi: bergabung, pilih, agregat, dll ... ketika kondisi tertentu berlaku.
Singkatnya, pembuatan kode seperti yang Anda pikir adalah ide yang buruk. Mungkin Anda harus melihat diagram ini untuk melihat bagaimana DB memecahkan masalah yang serupa dengan Anda:
sumber
Anda mungkin ingin memeriksa apakah Anda masih dapat menggunakan beberapa abstraksi yang masuk akal dan menggunakan misalnya pola metode templat untuk menulis kode yang dapat dimengerti untuk fungsionalitas umum dan memindahkan perbedaan antara metode ke dalam "operasi primitif" (sesuai dengan pola descrition) di 12 subkelas. Ini akan sangat meningkatkan rawatan dan pengujian, dan itu mungkin sebenarnya memiliki kinerja yang sama dengan kode saat ini, karena JVM dapat inline metode panggilan untuk operasi primitif setelah beberapa saat. Tentu saja, Anda harus memeriksa ini dalam tes kinerja.
sumber
Anda dapat memecahkan masalah metode khusus dengan menggunakan bahasa Scala.
Scala dapat inline metode, ini (dalam kombinasi dengan penggunaan fungsi urutan lebih tinggi mudah) memungkinkan untuk menghindari duplikasi kode gratis - ini sepertinya masalah utama yang disebutkan dalam jawaban Anda.
Tetapi juga, Scala memiliki macro sintaksis, yang memungkinkan untuk melakukan banyak hal dengan kode pada waktu kompilasi dengan cara yang aman.
Dan masalah umum dari tipe tinju primitif ketika digunakan dalam obat generik adalah mungkin untuk diselesaikan di Scala, juga: ia dapat melakukan spesialisasi generik untuk primitif untuk menghindari tinju secara otomatis dengan menggunakan
@specialized
anotasi - hal ini dibangun ke dalam bahasa itu sendiri. Jadi, pada dasarnya, Anda akan menulis satu metode generik di Scala, dan itu akan berjalan dengan kecepatan metode khusus. Dan jika Anda memerlukan aritmatika generik cepat juga, itu mudah dilakukan dengan menggunakan "pola" Typeclass untuk menyuntikkan operasi dan nilai-nilai untuk berbagai jenis numerik.Juga, Scala mengagumkan dalam banyak hal. Dan Anda tidak perlu menulis ulang semua kode ke Scala, karena Scala <-> interoperabilitas Java sangat baik. Pastikan untuk menggunakan SBT (scala build tool) untuk membangun proyek.
sumber
Jika fungsi yang dipermasalahkan besar, mengubah bit "mode / paradigma" menjadi antarmuka dan kemudian mengirimkan objek yang mengimplementasikan antarmuka itu sebagai parameter agar fungsi tersebut dapat berfungsi. GoF menyebut ini pola "Strategi", iirc. Jika fungsinya kecil, peningkatan overhead mungkin signifikan ... apakah seseorang menyebutkan profil belum? ... lebih banyak orang harus menyebutkan profil.
sumber
Berapa umur program? Sebagian besar perangkat keras yang lebih baru mungkin akan menghilangkan hambatan dan Anda dapat beralih ke versi yang lebih mudah dikelola. Tetapi perlu ada alasan untuk pemeliharaan, jadi kecuali tugas Anda adalah meningkatkan basis kode, biarkan seperti itu berfungsi.
sumber