Jadi melihat-lihat sebelumnya saya perhatikan beberapa komentar tentang metode panjang menjadi praktik yang buruk.
Saya tidak yakin saya selalu setuju bahwa metode panjang itu buruk (dan ingin pendapat dari orang lain).
Sebagai contoh, saya memiliki beberapa pandangan Django yang melakukan sedikit pemrosesan objek sebelum mengirimnya ke tampilan, metode yang panjang berupa 350 baris kode. Saya memiliki kode saya yang ditulis sehingga berkaitan dengan parameter - menyortir / memfilter queryset, kemudian sedikit demi sedikit melakukan beberapa pemrosesan pada objek permintaan saya telah kembali.
Jadi pemrosesan adalah agregasi kondisional, yang memiliki aturan yang cukup rumit sehingga tidak dapat dengan mudah dilakukan dalam database, jadi saya memiliki beberapa variabel yang dideklarasikan di luar loop utama kemudian diubah selama loop.
variable_1 = 0
variable_2 = 0
for object in queryset :
if object.condition_condition_a and variable_2 > 0 :
variable 1+= 1
.....
...
.
more conditions to alter the variables
return queryset, and context
Jadi menurut teori saya harus memfaktorkan semua kode menjadi metode yang lebih kecil, sehingga saya memiliki metode tampilan sebagai maksimum satu halaman.
Namun setelah bekerja pada berbagai basis kode di masa lalu, kadang-kadang saya menemukan itu membuat kode kurang mudah dibaca, ketika Anda harus terus-menerus melompat dari satu metode ke metode berikutnya mencari tahu semua bagian itu, sambil tetap menjaga metode terluar di kepala Anda.
Saya menemukan bahwa memiliki metode panjang yang diformat dengan baik, Anda dapat melihat logikanya dengan lebih mudah, karena tidak disembunyikan dalam metode batin.
Saya dapat memfaktorkan kode ke dalam metode yang lebih kecil, tetapi sering kali ada loop dalam yang digunakan untuk dua atau tiga hal, sehingga akan menghasilkan kode yang lebih kompleks, atau metode yang tidak melakukan satu hal kecuali dua atau tiga (alternatifnya) Saya bisa mengulangi loop batin untuk setiap tugas, tetapi kemudian akan ada hit kinerja).
Jadi adakah kasus bahwa metode panjang tidak selalu buruk? Apakah selalu ada kasus untuk metode menulis, ketika mereka hanya akan digunakan di satu tempat?
UPDATE: Sepertinya saya menanyakan pertanyaan ini lebih dari setahun yang lalu.
Jadi saya refactored kode setelah respon (campur) di sini, membaginya menjadi metode. Ini adalah aplikasi Django yang mengambil set kompleks objek terkait dari database, jadi argumen pengujiannya keluar (mungkin akan menghabiskan sebagian besar tahun ini untuk membuat objek yang relevan untuk kasus uji. Saya memiliki tipe "ini perlu dilakukan kemarin" lingkungan kerja sebelum ada yang mengeluh). Memperbaiki bug pada bagian kode itu sedikit lebih mudah sekarang, tetapi tidak secara masif.
sebelum :
#comment 1
bit of (uncomplicated) code 1a
bit of code 2a
#comment 2
bit of code 2a
bit of code 2b
bit of code 2c
#comment 3
bit of code 3
sekarang:
method_call_1
method_call_2
method_call_3
def method_1
bit of (uncomplicated) code 1a
bit of code 2a
def method_2
bit of code 2a
bit of code 2b
bit of code 2c
def method_3
bit of code 3
sumber
Jawaban:
Tidak, metode panjang tidak selalu buruk.
Dalam buku Code Complete , diukur bahwa metode yang panjang terkadang lebih cepat dan lebih mudah untuk ditulis, dan tidak mengarah ke masalah pemeliharaan.
Padahal, yang benar-benar penting adalah tetap KERING dan menghormati pemisahan kekhawatiran. Kadang-kadang, perhitungannya hanya panjang untuk ditulis, tetapi benar-benar tidak akan menyebabkan masalah di masa depan.
Namun, dari pengalaman pribadi saya, metode yang paling panjang cenderung tidak memiliki pemisahan perhatian. Sebenarnya, metode panjang adalah cara mudah untuk mendeteksi bahwa ada sesuatu yang mungkin salah dalam kode, dan bahwa perawatan khusus diperlukan di sini saat melakukan peninjauan kode.
EDIT: Saat komentar dibuat, saya menambahkan poin menarik pada jawabannya. Saya sebenarnya juga akan memeriksa metrik kompleksitas untuk fungsi (NPATH, kompleksitas siklomatik atau CRAP yang lebih baik).
Bahkan, saya sarankan untuk tidak memeriksa metrik tersebut pada fungsi yang panjang, tetapi untuk memasukkan peringatan pada mereka dengan alat otomatis (misalnya checkstyle untuk java misalnya) PADA SETIAP FUNGSI.
sumber
Sebagian besar fokus di sini tampaknya berada di sekitar kata selalu . Ya, absolut itu buruk, dan rekayasa perangkat lunak hampir sama seninya dengan sains, dan semua itu ... tapi saya harus mengatakan bahwa untuk contoh yang Anda berikan, metode ini akan lebih baik jika dibagi naik. Ini adalah argumen yang biasanya saya gunakan untuk membenarkan pemisahan metode Anda:
Keterbacaan: Saya tidak yakin tentang yang lain, tetapi saya tidak bisa membaca 350 baris kode dengan cepat. Ya, jika itu kode saya sendiri , dan saya bisa membuat banyak asumsi tentang hal itu, saya bisa membaca dengan sangat cepat, tapi itu intinya. Pertimbangkan seberapa mudah metode itu dibaca, jika terdiri dari 10 panggilan ke metode lain (masing-masing dengan nama deskriptif). Melakukan ini, Anda telah memperkenalkan layering dalam kode, dan metode tingkat tinggi memberikan garis besar, manis kepada pembaca mengenai apa yang terjadi.
Sunting - untuk menjelaskan hal itu, pikirkan seperti ini: bagaimana Anda menjelaskan metode itu kepada anggota tim baru? Tentunya ia memiliki beberapa struktur yang dapat Anda rangkum di sepanjang garis "well, ini dimulai dengan melakukan A, lalu B, lalu terkadang C, dll". Memiliki metode "ikhtisar" singkat yang memanggil metode lain membuat struktur ini jelas. Sangat jarang menemukan 350 baris kode yang tidak menguntungkan; otak manusia tidak dimaksudkan untuk berurusan dengan daftar 100-an item, kami mengelompokkannya.
Dapat digunakan kembali: Metode panjang cenderung memiliki kohesi yang rendah - mereka sering melakukan lebih dari satu hal. Kohesi rendah adalah musuh penggunaan kembali; jika Anda menggabungkan beberapa tugas menjadi satu metode, metode ini akan berakhir digunakan kembali di tempat yang lebih sedikit dari yang seharusnya.
Testabilitas dan kohesi: Saya menyebutkan kompleksitas siklomatik dalam komentar di atas - ini adalah ukuran yang cukup baik tentang seberapa kompleks metode Anda. Ini mewakili batas bawah jumlah jalur unik melalui kode Anda, tergantung pada input (edit: dikoreksi sesuai komentar MichaelT). Ini juga berarti bahwa untuk menguji metode Anda dengan benar, Anda harus memiliki sedikitnya kasus uji sebanyak jumlah kompleksitas siklomatik Anda. Sayangnya, ketika Anda mengumpulkan potongan-potongan kode yang tidak benar-benar bergantung satu sama lain, tidak ada cara untuk memastikan kurangnya ketergantungan ini, dan kompleksitasnya cenderung bertambah banyak. Anda dapat menganggap ukuran ini sebagai indikasi jumlah hal berbeda yang ingin Anda lakukan. Jika terlalu tinggi, saatnya untuk memecah belah dan menaklukkan.
Refactoring dan struktur: Metode panjang sering merupakan pertanda bahwa beberapa struktur kurang dalam kode. Seringkali, pengembang tidak dapat menemukan kesamaan antara bagian-bagian yang berbeda dari metode itu, dan di mana garis dapat ditarik di antara mereka. Menyadari bahwa metode yang panjang adalah masalah, dan mencoba membaginya menjadi metode yang lebih kecil adalah langkah pertama di jalan yang lebih panjang untuk benar-benar mengidentifikasi struktur yang lebih baik untuk semuanya. Mungkin Anda perlu membuat satu atau dua kelas; pada akhirnya tidak akan menjadi lebih kompleks!
Saya juga berpikir bahwa dalam kasus ini, alasan untuk memiliki metode yang panjang adalah "... beberapa variabel yang dideklarasikan di luar loop utama kemudian diubah selama loop". Saya bukan ahli tentang Python, tapi saya cukup yakin bahwa masalah ini bisa diperbaiki oleh beberapa bentuk lewat referensi.
sumber
someVar.toString()
dan merasakan Anda perlu melihat kode toString untuk mengetahui apa yang dilakukannya? Anda baru saja membaca melewatinya karena penamaan metode yang baik.Metode panjang selalu buruk, tetapi terkadang lebih baik daripada alternatifnya.
sumber
Metode panjang adalah bau kode . Mereka biasanya menunjukkan bahwa ada sesuatu yang salah, tetapi itu bukan aturan yang sulit dan cepat. Biasanya, kasus-kasus di mana mereka dibenarkan melibatkan banyak negara dan aturan bisnis yang cukup kompleks (seperti yang Anda temukan).
Mengenai pertanyaan Anda yang lain, sering kali membantu untuk memisahkan potongan-potongan logika menjadi metode-metode terpisah, bahkan jika mereka hanya dipanggil sekali. Itu membuatnya lebih mudah untuk melihat logika tingkat tinggi dan dapat membuat pengecualian menangani sedikit lebih bersih. Asalkan Anda tidak harus memasukkan dua puluh parameter untuk mewakili status pemrosesan!
sumber
Metode panjang tidak selalu buruk. Mereka biasanya merupakan tanda bahwa mungkin ada masalah.
Pada sistem yang saya kerjakan kami memiliki sekitar setengah lusin metode yang panjangnya lebih dari 10.000 baris. Satu saat ini panjangnya 54.830 baris. Dan tidak apa-apa.
Fungsi-fungsi yang sangat panjang ini sangat sederhana dan dibuat otomatis. Monster 54,830 garis panjang besar itu berisi data gerakan kutub harian dari 1 Januari 1962 hingga 10 Januari 2012 (rilis terakhir kami). Kami juga merilis prosedur di mana pengguna kami dapat memperbarui file yang dibuat otomatis itu. File sumber itu berisi data gerakan kutub dari http://data.iers.org/products/214/14443/orig/eopc04_08_IAU2000.62- sekarang , diterjemahkan secara otomatis ke C ++.
Membaca situs web tersebut dengan cepat tidak dimungkinkan dalam pemasangan yang aman. Tidak ada koneksi ke dunia luar. Mengunduh situs web sebagai salinan lokal dan mem-parsing dalam C ++ juga bukan pilihan; parsing lambat , dan ini harus cepat. Mengunduh, menerjemahkan otomatis ke C ++, dan mengkompilasi: Sekarang Anda memiliki sesuatu yang cepat. (Hanya saja jangan mengkompilasinya dioptimalkan. Sungguh menakjubkan berapa lama kompiler pengoptimal yang dibutuhkan untuk mengkompilasi 50.000 baris kode garis lurus sangat sederhana. Dibutuhkan lebih dari setengah jam di komputer saya untuk mengkompilasi satu file yang dioptimalkan. Dan pengoptimalan tidak menghasilkan apa-apa sama sekali. Tidak ada yang dioptimalkan. Ini kode garis lurus sederhana, satu pernyataan tugas setelah yang lain.)
sumber
Katakan saja ada cara yang baik dan buruk untuk memecah metode yang panjang. Harus "[menyimpan] metode terluar di kepala Anda" adalah tanda bahwa Anda tidak memecahnya dengan cara yang paling optimal, atau bahwa submethods Anda diberi nama yang buruk. Secara teori, ada contoh di mana metode panjang lebih baik. Dalam praktiknya, ini sangat jarang. Jika Anda tidak dapat menemukan cara membuat metode yang lebih pendek dapat dibaca, mintalah seseorang untuk meninjau kode Anda, dan minta mereka secara khusus untuk gagasan tentang memperpendek metode.
Adapun beberapa loop yang menyebabkan kinerja seharusnya, tidak ada cara untuk mengetahui itu tanpa mengukur. Beberapa loop yang lebih kecil dapat secara signifikan lebih cepat jika itu berarti semua yang dibutuhkannya dapat tetap dalam cache. Bahkan jika ada hit kinerja, biasanya diabaikan demi keterbacaan.
Saya akan mengatakan bahwa seringkali metode yang panjang lebih mudah untuk ditulis , meskipun metode itu lebih sulit dibaca . Itu sebabnya mereka berkembang biak meskipun tidak ada yang menyukainya. Tidak ada yang salah dengan perencanaan dari awal hingga refactor sebelum Anda memeriksanya.
sumber
Metode panjang bisa lebih komputasional dan hemat ruang, bisa lebih mudah untuk melihat logika dan lebih mudah untuk men-debug mereka. Namun aturan ini hanya benar-benar berlaku ketika hanya satu programmer yang menyentuh kode itu. Kode ini akan menjadi sakit untuk diperluas jika bukan atom, pada dasarnya orang berikutnya harus mulai dari awal dan kemudian men-debug dan menguji ini akan berlangsung selamanya karena tidak menggunakan kode yang dikenal baik.
sumber
Ada sesuatu yang kami sebut Dekomposisi Fungsional yang menyiratkan untuk memecah metode Anda yang lebih panjang menjadi metode yang lebih kecil sedapat mungkin. Seperti yang Anda sebutkan bahwa metode Anda melibatkan penyortiran / penyaringan maka Anda lebih baik memiliki metode atau fungsi terpisah untuk tugas-tugas ini.
Tepatnya, metode Anda harus difokuskan hanya pada 1 tugas saja.
Dan jika perlu memanggil metode lain karena beberapa alasan maka lakukan sebaliknya melanjutkan dengan yang sudah Anda tulis. Juga untuk pruposis keterbacaan, Anda dapat menambahkan komentar. Secara konvensional, programmer menggunakan komentar multi-line (/ ** / dalam C, C ++, C # dan Java) untuk deskripsi metode dan menggunakan komentar single-line (// dalam C, C ++, C # dan Java). Ada juga alat dokumentasi yang baik tersedia untuk keterbacaan kode yang lebih besar (mis. JavaDoc ). Anda juga dapat melihat komentar berbasis XML jika Anda adalah pengembang .Net.
Loop mempengaruhi kinerja program dan dapat menyebabkan overhead aplikasi jika tidak digunakan dengan benar. Idenya adalah untuk merancang algoritma Anda sedemikian rupa sehingga Anda menggunakan loop bersarang sesedikit mungkin.
sumber
Tidak apa-apa menulis fungsi yang panjang. Tetapi itu bervariasi pada konteks apakah Anda benar-benar membutuhkan atau tidak. Untuk misalnya beberapa algorthms terbaik dinyatakan terbaik ketika suatu bagian. Di sisi lain, sebagian besar rutin dalam program berorientasi objek akan menjadi rutinitas accessor, yang akan sangat singkat. Beberapa rutin pemrosesan yang panjang yang memiliki sakelar yang panjang, jika kondisinya dapat dioptimalkan melalui metode yang digerakkan oleh tabel.
Ada diskusi singkat yang sangat baik dalam Kode Lengkap 2 tentang panjang rutinitas.
sumber
Suara lain yang hampir selalu salah. Saya menemukan dua kasus dasar di mana itu adalah jawaban yang tepat, meskipun:
1) Suatu metode yang pada dasarnya hanya memanggil banyak metode lain dan tidak melakukan pekerjaan nyata itu sendiri. Anda memiliki proses yang membutuhkan 50 langkah untuk diselesaikan, Anda mendapatkan metode dengan 50 panggilan di dalamnya. Biasanya tidak ada yang bisa diperoleh dengan mencoba memecahnya.
2) Dispatcher. Desain OOP telah menghilangkan sebagian besar metode tersebut tetapi sumber data yang masuk pada dasarnya adalah data saja dan dengan demikian tidak dapat mengikuti prinsip-prinsip OOP. Bukan hal yang aneh untuk memiliki semacam rutin dispatcher dalam kode yang menangani data.
Saya juga akan mengatakan bahwa seseorang seharusnya tidak mempertimbangkan pertanyaan ketika berhadapan dengan hal-hal yang di-autogenerasi. Tidak ada yang mencoba memahami apa yang dilakukan kode autogenerated, tidak ada artinya sedikitpun apakah mudah bagi manusia untuk mengerti.
sumber
Saya ingin membahas contoh yang Anda berikan:
Di perusahaan saya, proyek terbesar kami dibangun di Django dan kami juga memiliki fungsi tampilan panjang (banyak lebih dari 350 baris). Saya berpendapat bahwa kita tidak perlu selama itu, dan mereka menyakiti kita.
Fungsi tampilan ini melakukan banyak pekerjaan terkait longgar yang harus diekstraksi ke model, kelas helper, atau fungsi helper. Selain itu, kami akhirnya menggunakan kembali pandangan untuk melakukan hal-hal yang berbeda, yang sebaliknya harus dibagi menjadi pandangan yang lebih kohesif.
Saya menduga pandangan Anda memiliki karakteristik serupa. Dalam kasus saya, saya tahu itu menyebabkan masalah dan saya sedang bekerja untuk membuat perubahan. Jika Anda tidak setuju bahwa itu menyebabkan masalah, maka Anda tidak perlu memperbaikinya.
sumber
Saya tidak tahu apakah seseorang telah menyebutkan ini, tetapi salah satu alasan mengapa metode yang lama itu buruk adalah karena mereka biasanya melibatkan beberapa tingkat abstraksi yang berbeda. Anda memiliki variabel lingkaran dan segala macam hal terjadi. Pertimbangkan fungsi fiktif:
Jika Anda melakukan semua animasi, perhitungan, akses data dll dalam fungsi itu akan berantakan. Fungsi nextSlide () menjaga lapisan abstraksi yang konsisten (sistem slide state) dan mengabaikan yang lain. Ini membuat kode dapat dibaca.
Jika Anda harus terus-menerus melangkah ke metode yang lebih kecil untuk melihat apa yang mereka lakukan, maka upaya membagi fungsi gagal. Hanya karena kode yang Anda baca tidak melakukan hal-hal yang jelas dalam metode anak tidak berarti metode anak adalah ide yang buruk, hanya saja itu dilakukan secara tidak benar.
Ketika saya membuat metode, saya biasanya membaginya menjadi metode yang lebih kecil sebagai semacam strategi membagi dan menaklukkan. Metode seperti
tentu lebih mudah dibaca daripada
Baik?
Saya setuju tentang pernyataan absolut yang buruk dan juga setuju bahwa biasanya metode yang panjang itu buruk.
sumber
Kisah nyata. Saya pernah menemukan metode yang panjangnya lebih dari dua ribu baris. Metode ini memiliki daerah yang menggambarkan apa yang dilakukannya di daerah tersebut. Setelah membaca suatu wilayah, saya memutuskan untuk melakukan metode ekstrak otomatis, menamainya sesuai dengan nama wilayah. pada saat saya selesai, metode itu tidak lebih dari 40 metode panggilan masing-masing sekitar lima puluh baris dan semuanya bekerja sama.
Apa yang terlalu besar itu subjektif. Terkadang, suatu metode tidak dapat dipecah lebih jauh dari apa yang ada saat ini. Ini seperti menulis buku. Kebanyakan orang setuju bahwa paragraf panjang biasanya harus dibagi. Tetapi kadang-kadang, hanya ada satu ide dan membaginya menyebabkan lebih banyak kebingungan daripada yang disebabkan oleh panjangnya paragraf itu.
sumber
Inti dari suatu metode adalah membantu mengurangi regurgitasi kode. Suatu metode harus memiliki fungsi spesifik yang menjadi tanggung jawabnya. Jika Anda akhirnya mengulangi kode di banyak tempat Anda berisiko kode memiliki hasil yang tidak terduga jika spesifikasi perangkat lunak yang dirancang untuk alamat diubah.
Untuk metode yang memiliki 350 baris akan menyarankan bahwa banyak tugas yang sedang dilakukan direplikasi di tempat lain karena tidak biasa untuk membutuhkan sejumlah besar kode untuk melakukan tugas khusus.
sumber
Ini bukan metode panjang yang merupakan praktik buruk, tetapi lebih membuat mereka seperti itu yang buruk.
Maksud saya tindakan aktual refactoring sampel Anda dari:
untuk
lalu ke
Anda sekarang dalam perjalanan menuju bukan hanya metode yang jauh lebih pendek tetapi jauh lebih bisa digunakan dan dimengerti.
sumber
Saya pikir fakta bahwa metode ini sangat panjang adalah sesuatu untuk diperiksa, tapi jelas bukan anti-pola instan. Hal besar yang harus dicari dalam metode besar adalah banyak bersarang. Jika Anda memiliki
dan badan loop tidak terlalu terlokalisasi (yaitu, Anda bisa mengirimkannya kurang dari 4 parameter), maka mungkin lebih baik untuk mengubahnya menjadi:
Pada gilirannya, ini dapat sangat mengurangi panjang fungsi. Juga, pastikan untuk mencari kode duplikat dalam fungsi dan memindahkannya ke fungsi yang terpisah
Akhirnya, beberapa metode hanya panjang dan rumit dan tidak ada yang dapat Anda lakukan. Beberapa masalah memerlukan solusi yang tidak mudah dikodekan. Sebagai contoh, menguraikan tata bahasa dengan banyak kompleksitas dapat membuat metode yang sangat panjang yang benar-benar tidak dapat Anda lakukan tanpa membuatnya lebih buruk.
sumber
Sebenarnya, itu tergantung. Seperti disebutkan, jika kode tidak memisahkan masalah dan mencoba melakukan segalanya dalam satu metode, maka ini merupakan masalah. Memisahkan kode menjadi beberapa modul membuatnya lebih mudah untuk membaca kode, serta menulis kode (oleh banyak programmer). Mengikuti satu modul (kelas) per file sumber adalah ide yang baik untuk memulai.
Kedua, ketika datang ke fungsi / prosedur:
adalah metode yang baik jika memeriksa kisaran hanya "Data". Ini adalah metode BAD ketika rentang yang sama berlaku untuk beberapa fungsi (contoh kode buruk):
Ini harus di refactored untuk:
Gunakan kembali kode sebanyak mungkin. Dan itu mungkin ketika setiap fungsi program Anda SEDERHANA (tidak harus mudah) cukup.
QUOTE: GUNUNG terdiri dari butiran kecil bumi. Lautan terdiri dari tetesan kecil air .. (- Sivananda)
sumber
Metode panjang cenderung ke arah "buruk" dalam bahasa imperatif yang mendukung pernyataan, efek samping, dan mutabilitas, justru karena fitur-fitur itu meningkatkan kompleksitas dan dengan demikian bug.
Dalam bahasa pemrograman fungsional, yang mendukung ekspresi, kemurnian, dan kekekalan, ada sedikit alasan untuk khawatir.
Dalam bahasa fungsional dan imperatif, selalu terbaik untuk memfaktorkan potongan kode yang dapat digunakan kembali ke dalam rutinitas tingkat atas yang umum, tetapi dalam bahasa fungsional yang mendukung pelingkupan leksikal dengan fungsi bersarang dll., Sebenarnya enkapsulasi yang lebih baik untuk menyembunyikan sub-rutin di bagian atas. -tingkat fungsi (metode) daripada memecahnya menjadi fungsi tingkat atas lainnya.
sumber