35 baris, 55 baris, 100 baris, 300 baris? Kapan Anda harus mulai memecahnya? Saya bertanya karena saya memiliki fungsi dengan 60 baris (termasuk komentar) dan sedang berpikir untuk memecahnya.
long_function(){ ... }
ke:
small_function_1(){...}
small_function_2(){...}
small_function_3(){...}
Fungsi tidak akan digunakan di luar fungsi long_, membuat fungsi yang lebih kecil berarti lebih banyak panggilan fungsi, dll.
Kapan Anda akan memecah suatu fungsi menjadi yang lebih kecil? Mengapa?
- Metode seharusnya hanya melakukan satu hal logis (pikirkan fungsionalitas)
- Anda harus dapat menjelaskan metode ini dalam satu kalimat
- Itu harus sesuai dengan ketinggian layar Anda
- Hindari overhead yang tidak perlu (komentar yang menunjukkan yang sudah jelas ...)
- Pengujian unit lebih mudah untuk fungsi logis kecil
- Periksa apakah bagian dari fungsi dapat digunakan kembali oleh kelas atau metode lain
- Hindari kopling antar kelas yang berlebihan
- Hindari struktur kontrol yang sangat bersarang
Terima kasih semuanya atas jawabannya , edit daftar dan pilih jawaban yang benar saya akan memilih yang itu;)
Saya refactoring sekarang dengan ide-ide itu dalam pikiran :)
function
refactoring
coding-style
pengguna58163
sumber
sumber
Jawaban:
Tidak ada aturan keras dan cepat untuk itu. Secara umum saya suka metode saya hanya "melakukan satu hal". Jadi jika itu mengambil data, lalu melakukan sesuatu dengan data itu, kemudian menulisnya ke disk maka saya akan membagi ambil dan menulis menjadi metode yang terpisah sehingga metode "utama" saya hanya berisi "melakukan sesuatu".
"Melakukan sesuatu" itu masih bisa menjadi beberapa baris, jadi saya tidak yakin beberapa baris adalah metrik yang tepat untuk digunakan :)
Sunting: Ini adalah satu baris kode yang saya kirimkan di tempat kerja minggu lalu (untuk membuktikan suatu hal .. itu bukan sesuatu yang saya biasakan :)) - Saya pasti tidak ingin 50-60 bocah nakal ini dalam metode saya : D
sumber
Berikut adalah daftar tanda merah (tanpa urutan tertentu) yang dapat menunjukkan bahwa suatu fungsi terlalu panjang:
Struktur kontrol yang bersarang : misalnya untuk loop 3 level atau bahkan hanya 2 level dengan pernyataan if bersarang yang memiliki kondisi kompleks.
Terlalu banyak parameter yang menentukan negara : Dengan parameter yang menentukan negara , maksud saya parameter fungsi yang menjamin jalur eksekusi tertentu melalui fungsi. Dapatkan terlalu banyak dari jenis parameter ini dan Anda memiliki ledakan kombinatorial dari jalur eksekusi (ini biasanya terjadi bersamaan dengan # 1).
Logika yang diduplikasi dalam metode lain : penggunaan kembali kode yang buruk adalah kontributor besar untuk kode prosedural monolitik. Banyak duplikasi logika seperti itu bisa sangat halus, tetapi begitu difaktorkan ulang, hasil akhirnya bisa menjadi desain yang jauh lebih elegan.
Kopling antar kelas yang berlebihan : kurangnya enkapsulasi yang tepat menghasilkan fungsi yang berkaitan dengan karakteristik intim dari kelas lain, sehingga memperpanjang mereka.
Overhead yang tidak perlu : Komentar yang menunjukkan kelas yang jelas, sangat bersarang, getter dan setter yang berlebihan untuk variabel kelas bersarang pribadi, dan nama fungsi / variabel yang panjang dapat membuat kebisingan sintaksis dalam fungsi terkait yang pada akhirnya akan menambah panjangnya.
Tampilan tingkat pengembang besar Anda tidak cukup besar untuk menampilkannya : Sebenarnya, tampilan hari ini cukup besar sehingga fungsi yang mendekati ketinggiannya mungkin terlalu lama. Tetapi, jika lebih besar , ini adalah senjata merokok bahwa ada sesuatu yang salah.
Anda tidak dapat segera menentukan tujuan fungsi : Selain itu, setelah Anda benar - benar menentukan tujuannya, jika Anda tidak dapat meringkas tujuan ini dalam satu kalimat atau kebetulan memiliki sakit kepala yang luar biasa, ini harus menjadi petunjuk.
Kesimpulannya, fungsi monolitik dapat memiliki konsekuensi yang luas dan seringkali merupakan gejala dari defisiensi desain utama. Setiap kali saya menemukan kode yang merupakan kegembiraan mutlak untuk dibaca, keanggunannya segera terlihat. Dan coba tebak: fungsinya seringkali sangat pendek.
sumber
// fetch Foo's credentials where Bar is "uncomplete"
. Itu hampir pasti nama fungsi di sana dan harus dipisahkan. Mungkin ingin di refactored menjadi sesuatu seperti:Foo.fetchCredentialWhereBarUncomplete()
Saya pikir ada peringatan besar untuk mantra "do only one thing" pada halaman ini. Terkadang melakukan satu hal menyulap banyak variabel. Jangan memecah fungsi panjang menjadi banyak fungsi yang lebih kecil jika fungsi yang lebih kecil akhirnya memiliki daftar parameter yang panjang. Melakukan hal itu hanya mengubah satu fungsi menjadi satu set fungsi yang sangat digabungkan tanpa nilai individu nyata.
sumber
Suatu fungsi seharusnya hanya melakukan satu hal. Jika Anda melakukan banyak hal kecil dalam suatu fungsi, buatlah setiap hal kecil berfungsi dan panggil fungsi-fungsi itu dari fungsi lama.
Apa yang benar - benar tidak ingin Anda lakukan adalah menyalin dan menempel setiap 10 baris fungsi panjang Anda ke fungsi pendek (seperti contoh Anda sarankan).
sumber
Saya setuju bahwa suatu fungsi seharusnya hanya melakukan satu hal, tetapi pada tingkat apa satu hal itu.
Jika 60 baris Anda mencapai satu hal (dari perspektif program Anda) dan potongan-potongan yang membentuk 60 baris itu tidak akan digunakan oleh hal lain, 60 baris itu baik-baik saja.
Tidak ada manfaat nyata untuk memecahnya, kecuali Anda dapat memecahnya menjadi potongan-potongan beton yang berdiri sendiri. Metrik yang digunakan adalah fungsionalitas dan bukan baris kode.
Saya telah bekerja di banyak program di mana penulis mengambil satu-satunya hal ke tingkat yang ekstrem dan yang akhirnya dilakukan adalah membuatnya tampak seperti seseorang membawa granat ke suatu fungsi / metode dan meledakkannya menjadi belasan potongan yang tidak terhubung yang sulit diikuti.
Saat mengeluarkan bagian-bagian dari fungsi itu, Anda juga perlu mempertimbangkan apakah Anda akan menambahkan overhead yang tidak perlu dan menghindari melewatkan sejumlah besar data.
Saya percaya kuncinya adalah mencari reuseability dalam fungsi yang panjang dan menarik bagian-bagian itu keluar. Yang tersisa adalah fungsi, apakah panjangnya 10, 20, atau 60 baris.
sumber
60 baris besar tetapi tidak terlalu panjang untuk suatu fungsi. Jika itu pas di satu layar di editor Anda bisa melihatnya sekaligus. Itu benar-benar tergantung pada apa fungsi yang dilakukan.
Mengapa saya dapat memecah suatu fungsi:
sumber
DoThisAndThisAndAlsoThis
fungsi yang sama tetapi dengan banyak abstraksi yang masih harus Anda sebutkan entah bagaimanaHeuristik pribadi saya adalah terlalu lama jika saya tidak dapat melihat semuanya tanpa menggulir.
sumber
Ukuran kira-kira ukuran layar Anda (jadi dapatkan layar lebar pivot besar dan putar) ... :-)
Di samping lelucon, satu hal logis per fungsi.
Dan hal positifnya adalah pengujian unit jauh lebih mudah dilakukan dengan fungsi logis kecil yang melakukan 1 hal. Fungsi besar yang melakukan banyak hal lebih sulit untuk diverifikasi!
/ Johan
sumber
Rule of thumb: Jika suatu fungsi berisi blok kode yang melakukan sesuatu, yang agak terlepas dari sisa kode, letakkan di fungsi yang terpisah. Contoh:
jauh lebih baik:
Pendekatan ini memiliki dua keunggulan:
Setiap kali Anda perlu mengambil alamat untuk kode pos tertentu, Anda dapat menggunakan fungsi yang tersedia.
Ketika Anda perlu membaca fungsi
build_address_list_for_zip()
lagi Anda tahu apa yang akan dilakukan oleh blok kode pertama (itu mengambil alamat untuk kode pos tertentu, setidaknya itulah yang dapat Anda peroleh dari nama fungsi). Jika Anda telah meninggalkan kode kueri sebaris, Anda harus terlebih dahulu menganalisis kode itu.[Di sisi lain (saya akan menolak saya katakan ini, bahkan di bawah siksaan): Jika Anda membaca banyak tentang optimasi PHP, Anda bisa mendapatkan ide untuk menjaga jumlah fungsi sekecil mungkin, karena pemanggilan fungsi sangat, sangat mahal di PHP. Saya tidak tahu tentang itu karena saya tidak pernah melakukan tolok ukur. Jika demikian, Anda mungkin lebih baik tidak mengikuti jawaban atas pertanyaan Anda jika aplikasi Anda sangat "sensitif kinerja" ;-)]
sumber
Mengintip siklomatik McCabe, di mana ia memecah kodenya menjadi grafik di mana, "Setiap node dalam grafik sesuai dengan blok kode dalam program di mana alirannya berurutan dan busur sesuai dengan cabang yang diambil dalam program. "
Sekarang bayangkan kode Anda tidak memiliki fungsi / metode; itu hanya satu bentangan besar kode dalam bentuk grafik.
Anda ingin memecah gepeng ini menjadi metode. Pertimbangkan itu, ketika Anda melakukannya, akan ada sejumlah blok dalam setiap metode. Hanya satu blok dari masing-masing metode yang akan terlihat oleh semua metode lain: blok pertama (kami menganggap Anda akan dapat melompat ke metode hanya pada satu titik: blok pertama). Semua blok lain dalam setiap metode akan menjadi informasi yang disembunyikan di dalam metode itu, tetapi setiap blok dalam suatu metode berpotensi melompat ke blok lain dalam metode itu.
Untuk menentukan ukuran metode Anda dalam hal jumlah blok per metode, satu pertanyaan yang mungkin Anda tanyakan pada diri sendiri adalah: berapa banyak metode yang harus saya miliki untuk meminimalkan jumlah potensi ketergantungan (MPE) maksimum di antara semua blok?
Jawaban itu diberikan oleh persamaan. Jika r adalah jumlah metode yang meminimalkan MPE sistem, dan n adalah jumlah blok dalam sistem, maka persamaannya adalah: r = sqrt (n)
Dan dapat ditunjukkan bahwa ini memberikan jumlah blok per metode menjadi, juga, sqrt (n).
sumber
Ingatlah bahwa Anda dapat berakhir dengan memfaktorkan ulang hanya untuk kepentingan ulang anjak piutang, berpotensi membuat kode lebih tidak dapat dibaca daripada sebelumnya.
Mantan kolega saya memiliki aturan aneh bahwa suatu fungsi / metode hanya boleh berisi 4 baris kode! Dia mencoba untuk berpegang teguh pada hal ini sehingga nama metodenya sering menjadi berulang & tidak berarti ditambah panggilan menjadi sangat bersarang & membingungkan.
Jadi mantra saya sendiri telah menjadi: jika Anda tidak bisa memikirkan nama fungsi / metode yang layak untuk potongan kode yang Anda re-factoring, jangan repot-repot.
sumber
Alasan utama saya biasanya memecah fungsi adalah karena potongan-potongan itu juga bahan dalam fungsi terdekat saya sedang menulis, sehingga bagian-bagian umum bisa diperhitungkan. Juga, jika menggunakan banyak bidang atau properti dari beberapa kelas lain, ada kemungkinan besar potongan yang relevan dapat dihapus secara grosir dan jika mungkin dipindahkan ke kelas lain.
Jika Anda memiliki blok kode dengan komentar di bagian atas, pertimbangkan menariknya ke dalam fungsi, dengan fungsi dan nama argumen yang menggambarkan tujuannya, dan menyimpan komentar untuk alasan kode.
Apakah Anda yakin tidak ada bagian di sana yang akan berguna di tempat lain? Fungsi macam apa itu?
sumber
Menurut pendapat saya jawabannya adalah: ketika itu melakukan terlalu banyak hal. Fungsi Anda harus melakukan hanya tindakan yang Anda harapkan dari nama fungsi itu sendiri. Hal lain yang perlu dipertimbangkan adalah jika Anda ingin menggunakan kembali beberapa bagian dari fungsi Anda di tempat lain; dalam hal ini bisa bermanfaat untuk membaginya.
sumber
Saya biasanya memecah fungsi oleh kebutuhan untuk menempatkan komentar yang menggambarkan blok kode berikutnya. Apa yang sebelumnya masuk ke komentar sekarang masuk ke nama fungsi baru. Ini bukan aturan yang sulit, tetapi (bagi saya) aturan praktis yang bagus. Saya suka berbicara kode untuk dirinya sendiri lebih baik daripada yang membutuhkan komentar (karena saya telah belajar bahwa komentar biasanya berbohong)
sumber
Ini sebagian adalah masalah selera, tetapi bagaimana saya menentukan ini adalah saya mencoba untuk menjaga fungsi saya kira-kira hanya selama akan muat di layar saya pada satu waktu (maksimal). Alasannya adalah bahwa lebih mudah untuk memahami apa yang terjadi jika Anda dapat melihat semuanya sekaligus.
Ketika saya kode, itu campuran menulis fungsi panjang, kemudian refactoring untuk menarik bit yang dapat digunakan kembali oleh fungsi lain - dan - menulis fungsi kecil yang melakukan tugas-tugas terpisah saat saya pergi.
Saya tidak tahu bahwa ada jawaban benar atau salah untuk ini (misalnya, Anda dapat menetapkan 67 baris sebagai maks Anda, tetapi mungkin ada saatnya masuk akal untuk menambahkan beberapa lagi).
sumber
Ada beberapa penelitian menyeluruh yang dilakukan pada topik ini, jika Anda ingin bug paling sedikit, kode Anda tidak boleh terlalu lama. Tapi itu juga tidak boleh terlalu pendek.
Saya tidak setuju bahwa suatu metode harus sesuai dengan tampilan Anda dalam satu, tetapi jika Anda menggulir ke bawah lebih dari satu halaman maka metode itu terlalu panjang.
Lihat Ukuran Kelas Optimal untuk Perangkat Lunak Berorientasi Objek untuk diskusi lebih lanjut.
sumber
Saya telah menulis 500 fungsi baris sebelumnya, namun ini hanya pernyataan peralihan besar untuk mendekode dan merespons pesan. Ketika kode untuk satu pesan menjadi lebih kompleks daripada satu jika-maka-lain, saya mengekstraknya.
Intinya, meskipun fungsinya 500 garis, wilayah yang dipelihara secara independen rata-rata 5 garis.
sumber
Saya biasanya menggunakan pendekatan tes didorong untuk menulis kode. Dalam pendekatan ini ukuran fungsi sering terkait dengan rincian pengujian Anda.
Jika tes Anda cukup fokus maka akan membuat Anda menulis fungsi fokus kecil untuk lulus ujian.
Ini juga bekerja ke arah lain. Fungsinya harus cukup kecil untuk diuji secara efektif. Jadi ketika bekerja dengan kode lama saya sering menemukan bahwa saya memecah fungsi yang lebih besar untuk menguji bagian-bagian yang berbeda.
Saya biasanya bertanya pada diri sendiri "apa tanggung jawab fungsi ini" dan jika saya tidak dapat menyatakan tanggung jawab dalam kalimat singkat yang jelas, dan kemudian menerjemahkannya menjadi tes fokus kecil, saya bertanya-tanya apakah fungsinya terlalu besar.
sumber
Jika memiliki lebih dari tiga cabang, umumnya ini berarti bahwa suatu fungsi atau metode harus dipecah, untuk merangkum logika percabangan dalam metode yang berbeda.
Masing-masing untuk loop, jika pernyataan, dll maka tidak dilihat sebagai cabang dalam metode panggilan.
Cobertura untuk kode Java (dan saya yakin ada alat lain untuk bahasa lain) menghitung jumlah jika, dll dalam suatu fungsi untuk setiap fungsi dan menjumlahkannya untuk "kompleksitas siklomatik rata-rata".
Jika fungsi / metode hanya memiliki tiga cabang, itu akan mendapatkan tiga pada metrik itu, yang sangat bagus.
Terkadang sulit untuk mengikuti pedoman ini, yaitu untuk memvalidasi input pengguna. Namun demikian menempatkan cabang dalam metode yang berbeda tidak hanya membantu pengembangan dan pemeliharaan tetapi pengujian juga, karena input ke metode yang melakukan percabangan dapat dianalisis dengan mudah untuk melihat input apa yang perlu ditambahkan ke kasus uji untuk menutupi cabang yang tidak tertutup.
Jika semua cabang berada di dalam metode tunggal, input harus dilacak sejak awal metode, yang menghambat testabilitas.
sumber
Saya kira Anda akan menemukan banyak jawaban untuk ini.
Saya mungkin akan memecahnya berdasarkan tugas logis yang sedang dilakukan dalam fungsi. Jika Anda melihat bahwa cerita pendek Anda berubah menjadi sebuah novel, saya sarankan mencari dan mengekstrak langkah-langkah yang berbeda.
Misalnya, jika Anda memiliki fungsi yang menangani beberapa jenis input string dan mengembalikan hasil string, Anda mungkin memecah fungsi berdasarkan logika untuk membagi string Anda menjadi beberapa bagian, logika untuk menambahkan karakter tambahan dan logika untuk memasukkannya semua kembali bersama lagi sebagai hasil yang diformat.
Singkatnya, apa pun yang membuat kode Anda bersih dan mudah dibaca (apakah itu hanya dengan memastikan fungsi Anda memiliki komentar yang baik atau memecahnya) adalah pendekatan terbaik.
sumber
dengan asumsi bahwa Anda melakukan satu hal, panjangnya akan tergantung pada:
60 baris mungkin terlalu panjang atau mungkin tepat. Saya curiga mungkin terlalu lama.
sumber
Satu hal (dan hal itu harus jelas dari nama fungsi), tetapi tidak lebih dari satu layar penuh kode, terlepas dari itu. Dan jangan ragu untuk menambah ukuran font Anda. Dan jika ragu, ubah menjadi dua fungsi atau lebih.
sumber
Memperluas semangat tweet dari Paman Bob beberapa waktu lalu, Anda tahu sebuah fungsi menjadi terlalu lama ketika Anda merasa perlu untuk menempatkan garis kosong di antara dua baris kode. Gagasannya adalah bahwa jika Anda memerlukan baris kosong untuk memisahkan kode, tanggung jawab dan ruang lingkupnya terpisah pada saat itu.
sumber
Gagasan saya adalah jika saya harus bertanya pada diri sendiri apakah terlalu lama, mungkin terlalu lama. Ini membantu membuat fungsi yang lebih kecil, di bidang ini, karena bisa membantu nanti dalam siklus hidup aplikasi.
sumber