Secara umum saya menggunakan metode pribadi untuk merangkum fungsionalitas yang digunakan kembali di banyak tempat di kelas. Tetapi kadang-kadang saya memiliki metode publik besar yang dapat dipecah menjadi langkah-langkah yang lebih kecil, masing-masing dengan metode pribadi. Ini akan membuat metode publik lebih pendek, tetapi saya khawatir bahwa memaksa siapa pun yang membaca metode untuk beralih ke metode pribadi yang berbeda akan merusak keterbacaan.
Apakah ada konsensus tentang ini? Apakah lebih baik memiliki metode publik yang panjang, atau memecahnya menjadi potongan-potongan kecil bahkan jika masing-masing bagian tidak dapat digunakan kembali?
coding-style
readability
Jordak
sumber
sumber
Jawaban:
Tidak, ini bukan gaya yang buruk. Sebenarnya itu adalah gaya yang sangat bagus.
Fungsi pribadi tidak perlu ada hanya karena usabilitas ulang. Itu tentu salah satu alasan bagus untuk membuatnya, tetapi ada alasan lain: dekomposisi.
Pertimbangkan fungsi yang terlalu banyak. Panjangnya seratus baris, dan mustahil dipikirkan.
Jika Anda membagi fungsi ini menjadi potongan-potongan kecil, itu masih "tidak" berfungsi sebanyak sebelumnya, tetapi dalam potongan-potongan kecil. Ini memanggil fungsi lain yang harus memiliki nama deskriptif. Fungsi utamanya membaca hampir seperti buku: lakukan A, lalu lakukan B, lalu lakukan C, dll. Fungsi-fungsi yang dipanggil hanya dapat dipanggil di satu tempat, tetapi sekarang mereka lebih kecil. Setiap fungsi tertentu harus dikosongkan dari fungsi lain: mereka memiliki cakupan yang berbeda.
Saat Anda menguraikan masalah besar menjadi masalah yang lebih kecil, bahkan jika masalah yang lebih kecil (fungsi) hanya digunakan / diselesaikan satu kali, Anda mendapatkan beberapa manfaat:
Keterbacaan. Tidak ada yang bisa membaca fungsi monolitik dan memahami apa yang dilakukannya sepenuhnya. Anda bisa terus membohongi diri sendiri, atau membaginya menjadi potongan seukuran gigitan yang masuk akal.
Lokalitas referensi. Sekarang menjadi tidak mungkin untuk mendeklarasikan dan menggunakan variabel, kemudian membuatnya bertahan, dan digunakan lagi 100 baris kemudian. Fungsi-fungsi ini memiliki cakupan yang berbeda.
Pengujian. Walaupun hanya perlu menguji unit anggota publik dari suatu kelas, mungkin diinginkan untuk menguji anggota pribadi tertentu juga. Jika ada bagian kritis dari fungsi panjang yang mungkin mendapat manfaat dari pengujian, tidak mungkin untuk mengujinya secara independen tanpa mengekstraksinya ke fungsi yang terpisah.
Modularitas. Sekarang Anda memiliki fungsi pribadi, Anda dapat menemukan satu atau lebih dari itu yang dapat diekstraksi ke dalam kelas yang terpisah, apakah itu hanya digunakan di sini atau dapat digunakan kembali. Untuk poin sebelumnya, kelas yang terpisah ini cenderung lebih mudah untuk diuji juga, karena akan membutuhkan antarmuka publik.
Gagasan untuk memecah kode besar menjadi potongan-potongan kecil yang lebih mudah dipahami dan diuji adalah poin kunci dari buku Kode Bersih Paman Bob . Pada saat menulis jawaban ini, bukunya berusia sembilan tahun, tetapi sama relevannya dengan zaman dulu.
sumber
Itu mungkin ide yang bagus!
Saya memang mengambil masalah dengan memecah urutan linear panjang aksi menjadi fungsi terpisah murni untuk mengurangi panjang fungsi rata-rata dalam basis kode Anda:
Sekarang Anda benar-benar telah menambahkan baris sumber dan mengurangi keterbacaan total. Apalagi jika Anda sekarang melewati banyak parameter antara masing-masing fungsi untuk melacak keadaan. Astaga!
Namun , jika Anda berhasil mengekstrak satu atau lebih baris menjadi fungsi murni yang melayani tujuan tunggal yang jelas ( bahkan jika dipanggil hanya sekali ), maka Anda telah meningkatkan keterbacaan:
Ini kemungkinan tidak akan mudah dalam situasi dunia nyata, tetapi bagian-bagian dari fungsionalitas murni seringkali dapat dihilangkan jika Anda memikirkannya cukup lama.
Anda akan tahu bahwa Anda berada di jalur yang benar ketika Anda memiliki fungsi dengan nama kata kerja yang bagus dan ketika fungsi orangtua Anda memanggil mereka dan semuanya secara praktis dibaca seperti paragraf prosa.
Kemudian ketika Anda kembali berminggu-minggu kemudian untuk menambahkan lebih banyak fungsi dan Anda menemukan bahwa Anda benar - benar dapat menggunakan kembali salah satu dari fungsi-fungsi itu, maka oh, sukacita yang meriah! Sungguh kegembiraan yang luar biasa bercahaya!
sumber
foo = compose(reglorbulate, deglorbFramb, getFrambulation);
Jawabannya sangat tergantung pada situasi. @Snowman membahas hal positif dari memecah fungsi publik yang besar, tetapi penting untuk diingat bahwa ada efek negatif juga, karena Anda benar-benar khawatir.
Banyak fungsi pribadi dengan efek samping dapat membuat kode sulit dibaca dan cukup rapuh. Ini terutama benar ketika fungsi-fungsi pribadi ini bergantung pada efek samping satu sama lain. Hindari memiliki fungsi yang digabungkan secara ketat.
Abstraksi bocor . Meskipun menyenangkan untuk berpura-pura bagaimana operasi dilakukan atau bagaimana data disimpan tidak masalah, ada beberapa kasus di mana itu dilakukan, dan penting untuk mengidentifikasi mereka.
Semantik dan konteks penting. Jika Anda gagal menangkap dengan jelas fungsi dari namanya, Anda dapat mengurangi keterbacaan dan meningkatkan kerapuhan fungsi publik. Ini terutama benar ketika Anda mulai membuat fungsi pribadi dengan sejumlah besar parameter input dan output. Dan sementara dari fungsi publik, Anda melihat apa fungsi pribadi yang dipanggil, dari fungsi pribadi, Anda tidak melihat apa fungsi publik menyebutnya. Ini dapat menyebabkan "perbaikan bug" dalam fungsi pribadi yang merusak fungsi publik.
Kode yang sangat terurai selalu lebih jelas bagi penulis daripada yang lain. Ini tidak berarti bahwa itu masih belum jelas bagi orang lain, tetapi mudah untuk mengatakan bahwa itu masuk akal yang
bar()
harus dipanggil sebelumnyafoo()
pada saat penulisan.Penggunaan kembali yang berbahaya. Fungsi publik Anda kemungkinan membatasi input apa yang mungkin untuk setiap fungsi pribadi. Jika asumsi input ini tidak ditangkap dengan benar (mendokumentasikan SEMUA asumsi sulit), seseorang mungkin menggunakan kembali salah satu fungsi pribadi Anda dengan tidak benar, memasukkan bug ke dalam basis kode.
Mengurai fungsi berdasarkan kohesi dan kopling internal, bukan panjang absolut.
sumber
MainMethod
(cukup mudah didapat, biasanya simbol disertakan dan Anda harus memiliki file simbol dereferensi) yang merupakan baris 2k (nomor baris tidak pernah dimasukkan dalam laporan bug) dan itu adalah NRE yang dapat terjadi pada 1k dari baris itu, baik saya akan terkutuk jika saya melihat ke dalamnya. Tetapi jika mereka mengatakan itu terjadi padaSomeSubMethodA
8 baris dan pengecualiannya adalah NRE, maka saya mungkin akan menemukan dan memperbaikinya dengan cukup mudah.IMHO, nilai mengeluarkan blok kode murni sebagai alat untuk memecah kompleksitas, akan sering dikaitkan dengan perbedaan dalam kompleksitas antara:
Deskripsi bahasa manusia yang lengkap dan akurat tentang apa yang dilakukan kode, termasuk bagaimana menangani kasus sudut , dan
Kode itu sendiri.
Jika kode ini jauh lebih rumit daripada deskripsi, mengganti kode in-line dengan panggilan fungsi dapat membuat kode di sekitarnya lebih mudah dimengerti. Di sisi lain, beberapa konsep dapat diekspresikan lebih mudah dalam bahasa komputer daripada dalam bahasa manusia. Saya akan menganggap
w=x+y+z;
, misalnya, lebih mudah dibaca daripadaw=addThreeNumbersAssumingSumOfFirstTwoDoesntOverflow(x,y,z);
.Ketika fungsi besar terpecah, akan ada semakin sedikit perbedaan di antara kompleksitas sub-fungsi versus deskripsi mereka, dan keuntungan dari subdivisi lebih lanjut akan berkurang. Jika ada beberapa hal yang terpecah sehingga deskripsi akan lebih rumit daripada kode, perpecahan lebih lanjut akan membuat kode lebih buruk.
sumber
int average3(int n1, int n2, int n3)
. Membagi fungsi "rata-rata" akan berarti bahwa seseorang yang ingin melihat apakah itu cocok untuk persyaratan harus mencari di dua tempat.Ini adalah tantangan penyeimbang.
Lebih baik lebih baik
Metode pribadi secara efektif memberikan nama untuk kode yang terkandung, dan kadang-kadang tanda tangan yang bermakna (kecuali setengah dari parameternya sepenuhnya data ad-hoc tramp dengan saling ketergantungan yang tidak jelas dan tidak terdokumentasi).
Memberi nama untuk kode konstruksi umumnya baik, selama nama-nama tersebut menyarankan kontrak yang bermakna bagi penelepon, dan kontrak metode pribadi secara akurat sesuai dengan apa yang disarankan oleh namanya.
Dengan memaksa diri untuk memikirkan kontrak yang berarti untuk bagian kode yang lebih kecil, pengembang awal dapat menemukan beberapa bug dan menghindarinya tanpa rasa sakit bahkan sebelum pengujian dev. Ini hanya berfungsi jika pengembang berusaha untuk penamaan ringkas (terdengar sederhana tapi akurat) dan bersedia untuk menyesuaikan batas-batas metode pribadi sehingga penamaan ringkas bahkan mungkin.
Pemeliharaan selanjutnya juga terbantu, karena penamaan tambahan membantu membuat kode tersebut didokumentasikan sendiri .
Sampai terlalu baik
Apakah mungkin untuk memberi nama secara berlebihan pada potongan kode kecil, dan berakhir dengan terlalu banyak, metode pribadi yang terlalu kecil? Tentu. Satu atau lebih dari gejala berikut menunjukkan bahwa metode menjadi terlalu kecil untuk berguna:
XxxInternal
atauDoXxx
, terutama jika tidak ada skema terpadu dalam memperkenalkannya.LogDiskSpaceConsumptionUnlessNoUpdateNeeded
sumber
Berlawanan dengan apa yang dikatakan orang lain, saya berpendapat bahwa metode publik yang panjang adalah aroma desain yang tidak diperbaiki dengan mendekomposisi menjadi metode pribadi.
Jika ini masalahnya maka saya berpendapat setiap langkah harus menjadi warga negara kelas satu dengan tanggung jawab tunggal masing-masing. Dalam paradigma berorientasi objek, saya akan menyarankan untuk membuat antarmuka dan implementasi untuk setiap langkah sedemikian rupa sehingga masing-masing memiliki tanggung jawab tunggal yang mudah diidentifikasi dan dapat dinamai dengan cara yang tanggung jawabnya jelas. Ini memungkinkan Anda untuk menguji unit metode publik besar (sebelumnya), serta setiap langkah individu secara independen satu sama lain. Mereka semua harus didokumentasikan juga.
Mengapa tidak terurai menjadi metode pribadi? Berikut ini beberapa alasan:
Ini adalah argumen yang saya miliki dengan salah satu rekan saya baru-baru ini. Dia berpendapat bahwa memiliki seluruh perilaku modul dalam file / metode yang sama meningkatkan keterbacaan. Saya setuju bahwa kode lebih mudah untuk diikuti ketika semua bersama-sama, tetapi kode ini kurang mudah untuk dipikirkan ketika kompleksitas bertambah. Ketika sebuah sistem tumbuh, ia menjadi sulit untuk dipikirkan tentang keseluruhan modul secara keseluruhan. Ketika Anda menguraikan logika kompleks menjadi beberapa kelas masing-masing dengan responsiblity tunggal, maka itu menjadi lebih mudah untuk alasan tentang setiap bagian.
sumber