Teknik untuk meminimalkan jumlah argumen fungsi

13

Dalam Clean Code, ada tertulis bahwa "jumlah ideal argumen untuk suatu fungsi adalah nol". Alasan mengapa dijelaskan dan masuk akal. Apa yang saya kejar adalah teknik untuk memperbaiki metode dengan 4 atau lebih argumen untuk menyelesaikan masalah ini.

Salah satu caranya adalah mengekstraksi argumen ke dalam kelas baru, tetapi itu pasti akan menyebabkan ledakan kelas? Dan kelas-kelas itu cenderung berakhir dengan nama yang melanggar beberapa aturan penamaan (diakhiri dengan "Data" atau "Info" dll)?

Teknik lain adalah membuat variabel yang digunakan oleh banyak fungsi sebagai variabel anggota pribadi untuk menghindari melewatinya, tetapi itu memperluas ruang lingkup variabel, mungkin sedemikian sehingga terbuka untuk fungsi yang sebenarnya tidak membutuhkannya.

Hanya mencari cara untuk meminimalkan argumen fungsi, setelah menerima alasan mengapa itu ide yang baik untuk melakukannya.

Neil Barnwell
sumber
21
Tbh saya tidak setuju dengan kode bersih sama sekali. Jika jumlah argumen ke fungsi adalah nol maka itu menyiratkan bahwa fungsi tersebut memiliki efek samping dan mungkin mengubah keadaan di suatu tempat. Sementara saya setuju bahwa kurang dari 4 argumen mungkin aturan praktis yang baik - saya lebih suka memiliki fungsi dengan 8 argumen yang statis dan tidak memiliki efek samping daripada fungsi non-statis dengan argumen nol yang mengubah keadaan dan memiliki efek samping .
wasatz
4
" Dalam Clean Code, ada tertulis bahwa" jumlah ideal argumen untuk suatu fungsi adalah nol ". " Sungguh? Itu sangat salah! Jumlah parameter ideal adalah satu, dengan nilai balik yang ditentukan secara deterministik dari satu parameter tersebut. Dalam praktiknya, jumlah parameter tidak terlalu penting; yang penting adalah, jika memungkinkan, fungsi harus murni (yaitu, ia mendapatkan nilai kembali hanya dari parameternya tanpa efek samping).
David Arno
2
Nah, buku itu kemudian melanjutkan untuk menunjukkan bahwa efek sampingnya tidak diinginkan ...
Neil Barnwell
2
Kemungkinan duplikat Strategi untuk pembungkus parameter
nyamuk

Jawaban:

16

Yang paling penting untuk diingat adalah bahwa itu adalah pedoman, bukan aturan.

Ada kasus di mana suatu metode harus mengambil argumen. Pikirkan tentang +metode angka, misalnya. Atau addmetode untuk koleksi.

Bahkan, orang mungkin bahkan berpendapat bahwa apa artinya menambahkan dua angka tergantung pada konteks, misalnya dalam ℤ 3 + 3 == 6, tetapi dalam ℤ | 5 3 + 3 == 2 , jadi benar-benar operator tambahan harus menjadi metode pada objek konteks yang mengambil dua argumen alih-alih sebuah metode pada angka yang mengambil satu argumen.

Demikian juga, metode untuk membandingkan dua objek harus berupa metode dari satu objek mengambil yang lain sebagai argumen, atau metode konteks, mengambil dua objek sebagai argumen, sehingga tidak masuk akal untuk memiliki metode perbandingan dengan kurang dari satu argumen.

Yang mengatakan, ada beberapa hal yang dapat dilakukan untuk mengurangi jumlah argumen untuk suatu metode:

  • Buat metode itu sendiri lebih kecil : Mungkin, jika metode itu membutuhkan banyak argumen, itu terlalu banyak?
  • Abstraksi yang hilang : Jika argumen berkorelasi erat, mungkin mereka bersatu, dan ada abstraksi yang Anda lewatkan? (Contoh buku teks Canonical: alih-alih dua koordinat, meneruskan Pointobjek, atau alih-alih mengirimkan nama pengguna dan email, kirimkan IdCardobjek.)
  • Status objek : Jika argumen diperlukan oleh beberapa metode, mungkin argumen tersebut harus menjadi bagian dari status objek. Jika hanya diperlukan oleh beberapa metode tetapi tidak yang lain, mungkin objek melakukan terlalu banyak dan harus benar-benar menjadi dua objek.

Salah satu caranya adalah mengekstraksi argumen ke dalam kelas baru, tetapi itu pasti akan menyebabkan ledakan kelas?

Jika model domain Anda memiliki berbagai jenis hal, maka kode Anda akan berakhir dengan berbagai jenis objek. Tidak ada yang salah dengan itu.

Dan kelas-kelas itu cenderung berakhir dengan nama yang melanggar beberapa aturan penamaan (diakhiri dengan "Data" atau "Info" dll)?

Jika Anda tidak dapat menemukan nama yang tepat, mungkin Anda mengelompokkan terlalu banyak argumen bersama atau terlalu sedikit. Jadi, Anda hanya memiliki sebuah fragmen kelas atau Anda memiliki lebih dari satu kelas.

Teknik lain adalah membuat variabel yang digunakan oleh banyak fungsi sebagai variabel anggota pribadi untuk menghindari melewatinya, tetapi itu memperluas ruang lingkup variabel, mungkin sedemikian sehingga terbuka untuk fungsi yang sebenarnya tidak membutuhkannya.

Jika Anda memiliki sekelompok metode yang semuanya beroperasi pada argumen yang sama, dan kelompok metode lain yang tidak, mungkin mereka termasuk dalam kelas yang berbeda.

Perhatikan seberapa sering saya menggunakan kata "mungkin"? Itu sebabnya itu adalah pedoman, bukan aturan. Mungkin metode Anda dengan 4 parameter baik-baik saja!

Jörg W Mittag
sumber
7
@ BrunoSchäpper: Tentu: (1) " Buat metodenya sendiri lebih kecil: Mungkin, jika metodenya membutuhkan banyak argumen, itu terlalu banyak? ". Jumlah params adalah ujian yang buruk untuk ini. Params opsional / boolean dan banyak baris kode adalah indikator kuat dari metode yang melakukan terlalu banyak. Banyak params yang paling lemah. (2) " Status objek: Jika argumen diperlukan oleh beberapa metode, mungkin itu harus menjadi bagian dari status objek ". Tidak, tidak, dan tiga kali, tidak. Minimalkan keadaan objek; bukan parameter fungsi. Jika mungkin, berikan nilai ke semua metode melalui parameter untuk menghindari status objek.
David Arno
Contoh yang Anda berikan untuk penambahan adalah kesalahan total. The addfungsi untuk nomor alam dan addfungsi untuk cincin bilangan bulat mod n dua fungsi tindakan yang berbeda pada dua jenis yang berbeda. Saya juga tidak mengerti apa yang Anda maksud dengan "konteks".
gardenhead
Thx @DavidArno. 1) setuju, bukan indikator kuat dalam dan dari dirinya sendiri. Tapi tetap saja bagus. Saya sering melihat beberapa metode, dengan beberapa objek dilewati diseluruh. Tidak ada status objek. Itu bagus, tapi 2) IMHO pilihan yang lebih baik adalah refactoring metode tersebut, pindahkan negara implisit ke kelas baru, yang mengambil semua params ini sebagai argumen eksplisit. Anda berakhir dengan satu metode argumen nol publik, dan banyak metode internal argumen nol-ke-satu. Negara tidak terbuka untuk umum, global atau bahkan tetap hidup, tetapi kode jauh lebih bersih.
Bruno Schäpper
6

Perhatikan bahwa argumen nol tidak menyiratkan efek samping, karena objek Anda adalah argumen implisit. Lihat berapa banyak metode zero-arity daftar abadi Scala , misalnya.

Salah satu teknik yang berguna saya sebut teknik "pemfokusan lensa". Saat Anda memfokuskan lensa kamera, lebih mudah untuk melihat titik fokus sebenarnya jika Anda mengambilnya terlalu jauh, lalu mundur ke titik yang benar. Hal yang sama berlaku untuk refactoring perangkat lunak.

Terutama jika Anda menggunakan kontrol versi terdistribusi, perubahan perangkat lunak mudah dilakukan dengan percobaan, lihat apakah Anda suka tampilannya, dan mundur jika tidak, tetapi karena alasan tertentu orang sering enggan melakukannya.

Dalam konteks pertanyaan Anda saat ini, itu berarti menulis versi argumen nol atau satu, dengan beberapa fungsi pemisahan terlebih dahulu, maka relatif mudah untuk melihat fungsi mana yang perlu digabungkan agar mudah dibaca.

Perhatikan bahwa penulis juga merupakan penganjur besar pengembangan yang digerakkan oleh tes, yang cenderung menghasilkan fungsi rendah arity pada awalnya karena Anda mulai dengan kasus-kasus tes sepele Anda.

Karl Bielefeldt
sumber
1
Seperti analogi "pemfokusan lensa" Anda - Terutama saat refactoring, penting untuk menggunakan lensa sudut lebar daripada yang close-up. Dan melihat # dari parameter terlalu dekat
tofro
0

Suatu pendekatan yang sederhana (dan naif - atau harus saya katakan secara membabi buta ) hanya bertujuan untuk mengurangi jumlah argumen ke fungsi ist mungkin salah. Sama sekali tidak ada yang salah dengan fungsi yang memiliki banyak argumen. Jika mereka diperlukan oleh logika, ya mereka diperlukan ... Daftar parameter yang panjang tidak membuat saya khawatir sama sekali - selama diformat dengan benar dan dikomentari agar mudah dibaca.

Jika semua atau sebagian argumen termasuk dalam satu entitas logis unik dan biasanya diedarkan secara berkelompok di seluruh program Anda, mungkin masuk akal untuk mengelompokkannya ke dalam wadah - Biasanya struct atau objek lain. Contoh umum mungkin semacam pesan atau tipe data acara .

Anda dapat dengan mudah melakukan pendekatan itu - begitu Anda menemukan bahwa mengepak dan membongkar barang ke dan dari wadah pengangkutan seperti itu menghasilkan lebih banyak overhead daripada meningkatkan pembacaan, Anda mungkin sudah melangkah terlalu jauh.

OTOH, daftar parameter besar dapat menjadi tanda bahwa program Anda mungkin tidak terstruktur dengan baik - mungkin fungsi yang memerlukan sejumlah besar parameter hanya mencoba melakukan terlalu banyak dan harus dipecah menjadi beberapa fungsi yang lebih kecil. Saya lebih suka mulai di sini daripada mengkhawatirkan # parameter.

tofro
sumber
5
Mengurangi jumlah argumen secara salah tentu saja salah. Tetapi saya tidak setuju dengan, "Sama sekali tidak ada yang salah dengan fungsi yang memiliki banyak argumen." . Menurut pendapat saya, ketika Anda menekan suatu fungsi dengan sejumlah besar argumen, dalam 99,9% dari semua kasus ada cara untuk memperbaiki struktur kode dengan cara yang disengaja yang (juga) mengurangi jumlah argumen dari fungsi tersebut.
Doc Brown
@DocBrown Itu sebabnya ada paragraf terakhir ini dan rekomendasi untuk memulai di sana .... Dan satu lagi: Anda mungkin tidak pernah mencoba memprogram melawan MS Windows API;)
tofro
"mungkin fungsi yang memerlukan sejumlah besar parameter hanya mencoba melakukan terlalu banyak dan harus dipecah menjadi beberapa fungsi yang lebih kecil." Saya sepenuhnya setuju, meskipun dalam praktiknya bukankah Anda hanya berakhir dengan fungsi lain yang lebih tinggi dari tumpukan yang memanggil beberapa fungsi yang lebih kecil? Anda kemudian bisa refactor mereka menjadi objek, tetapi objek itu akan memiliki ctor. Anda bisa menggunakan pembangun bla bla bla. Intinya adalah ini adalah regresi tanpa batas - di suatu tempat, ada sejumlah nilai yang diperlukan untuk perangkat lunak untuk melakukan pekerjaan itu, dan mereka harus mendapatkan fungsi-fungsi tersebut entah bagaimana.
Neil Barnwell
1
@NeilBarnwell Dalam kasus ideal (layak refactoring) Anda mungkin dapat membagi fungsi yang membutuhkan 10 argumen menjadi tiga yang masing-masing membutuhkan 3-4 argumen. Dalam kasus yang tidak terlalu ideal, Anda memiliki tiga fungsi yang masing-masing membutuhkan 10 argumen (lebih baik tinggalkan saja, kalau begitu). Berkenaan dengan argumen tumpukan yang lebih tinggi: Setuju - Mungkin terjadi, tetapi tidak harus - argumen berasal dari suatu tempat, dan bahwa pengambilan bisa di suatu tempat di dalam tumpukan juga dan hanya perlu dimasukkan ke tempat yang tepat di sana - Jarak tempuh cenderung bervariasi.
tofro
Logika perangkat lunak tidak pernah membutuhkan lebih dari empat parameter. Hanya sebuah kompiler yang mungkin.
theDoctor
0

Tidak ada cara ajaib: Anda harus menguasai domain masalah untuk menemukan arsitektur yang tepat. Itulah satu-satunya cara untuk refactor: menguasai domain masalah. Lebih dari empat parameter hanyalah taruhan pasti bahwa arsitektur Anda saat ini salah dan salah.

Satu-satunya pengecualian adalah kompiler (metaprogram) dan simulasi, di mana batasnya secara teoritis 8, tetapi mungkin hanya 5.

dokter
sumber