Kode Bersih: Fungsi dengan beberapa parameter [ditutup]

49

Saya membaca bab-bab pertama dari Clean Code oleh Robert C. Martin, dan menurut saya itu cukup bagus, tetapi saya ragu, di satu bagian disebutkan bahwa itu baik (secara kognitif) bahwa fungsi-fungsinya harus memiliki beberapa parameter. mungkin, bahkan menunjukkan bahwa 3 atau lebih parameter terlalu banyak untuk suatu fungsi (yang saya temukan sangat berlebihan dan idealis), jadi saya mulai bertanya-tanya ...

Kedua praktik menggunakan variabel global dan melewati banyak argumen pada fungsi akan menjadi praktik pemrograman yang buruk, tetapi penggunaan variabel global dapat sangat mengurangi jumlah parameter dalam fungsi ...

Jadi saya ingin mendengar pendapat Anda tentang itu, apakah ada baiknya menggunakan variabel global untuk mengurangi jumlah parameter fungsi atau tidak? Dalam kasus apa jadinya?

Apa yang saya pikirkan adalah bahwa itu tergantung pada beberapa faktor:

  • Ukuran kode sumber.
  • Jumlah parameter dalam rata-rata fungsi.
  • Jumlah fungsi.
  • Frekuensi di mana variabel yang sama digunakan.

Menurut pendapat saya jika ukuran kode sumber relatif kecil (seperti kurang dari 600 baris kode), ada banyak fungsi, variabel yang sama dilewatkan sebagai parameter dan fungsi memiliki banyak parameter, maka menggunakan variabel global akan bernilai, tetapi saya ingin tahu...

  • Apakah Anda membagikan pendapat saya?
  • Bagaimana menurut Anda tentang kasus-kasus lain di mana kode sumber lebih besar, dll?

PS . Saya melihat posting ini , judulnya sangat mirip, tetapi dia tidak bertanya apa yang ingin saya ketahui.

OiciTrap
sumber
144
Saya tidak berpikir alternatifnya adalah global, tetapi malah mengkonsolidasikan argumen menjadi objek. Ini mungkin lebih dari saran yang postLetter(string country, string town, string postcode, string streetAddress, int appartmentNumber, string careOf)merupakan versi bau postLetter(Address address). Terus membaca buku itu, semoga akan mengatakan sesuatu seperti itu.
Nathan Cooper
3
@DocBrown Saya mengambil pertanyaan yang berarti sesuatu yang lebih seperti Paman Bob mengatakan jangan gunakan lebih dari 3 params jadi saya menyelesaikan masalah itu dengan menggunakan variabel global kan? :-) Saya pikir kemungkinan penulis tidak tahu ada cara yang lebih baik untuk menyelesaikan masalah ini - seperti disebutkan dalam jawaban di bawah ini.
bytedev
9
Tidak lebih dari n parameter adalah aturan praktis (untuk nilai n), tidak terukir pada berlian. Jangan salah saran yang baik untuk mandat. Banyak parameter umumnya merupakan bau kode yang terlalu banyak terjadi dalam satu fungsi / metode. Orang-orang biasa menghindari pemisahan menjadi beberapa fungsi untuk menghindari penambahan biaya panggilan tambahan. Hanya sedikit aplikasi yang perf-intensif ini lagi dan profiler dapat memberi tahu Anda kapan dan di mana Anda perlu menghindari panggilan tambahan.
Jared Smith
14
Ini menunjukkan apa yang salah dengan aturan bebas penilaian semacam ini: aturan ini membuka pintu bagi 'solusi' bebas penilaian. Jika suatu fungsi memiliki banyak argumen, itu mungkin menunjukkan desain suboptimal, biasanya bukan hanya dari fungsi, tetapi dari konteks di mana ia digunakan. Solusinya (jika diperlukan) adalah berusaha untuk memperbaiki kode. Saya tidak bisa memberi Anda aturan sederhana, umum, bebas penilaian tentang cara melakukannya, tetapi itu tidak berarti bahwa 'tidak lebih dari argumen N' adalah aturan yang baik.
sdenham
4
Jika Anda memiliki terlalu banyak parameter untuk suatu fungsi, kemungkinan beberapa di antaranya terkait dan harus dikelompokkan menjadi objek yang kemudian menjadi parameter tunggal yang merangkum beberapa bagian data. Ada opsi ketiga di sini.

Jawaban:

113

Saya tidak membagikan pendapat Anda. Menurut pendapat saya menggunakan variabel global adalah praktik yang lebih buruk daripada lebih banyak parameter terlepas dari kualitas yang Anda jelaskan. Alasan saya adalah bahwa lebih banyak parameter dapat membuat metode lebih sulit untuk dipahami, tetapi variabel global dapat menyebabkan banyak masalah untuk kode termasuk testability yang buruk, bug konkurensi, dan kopling ketat. Tidak peduli berapa banyak parameter yang dimiliki fungsi, ia tidak akan memiliki masalah yang sama seperti variabel global.

... variabel yang sama dilewatkan sebagai parameter

Ini mungkin menjadi bau desain. Jika Anda memiliki parameter yang sama yang diteruskan ke sebagian besar fungsi di sistem Anda, mungkin ada masalah lintas sektoral yang harus ditangani dengan memperkenalkan komponen baru. Saya tidak berpikir meneruskan variabel yang sama ke banyak fungsi menjadi alasan yang masuk akal untuk memperkenalkan variabel global.

Dalam satu pengeditan pertanyaan Anda, Anda mengindikasikan bahwa memperkenalkan variabel global dapat meningkatkan keterbacaan kode. Saya tidak setuju. Penggunaan variabel global disembunyikan dalam kode implementasi sedangkan parameter fungsi dinyatakan dalam tanda tangan. Fungsi idealnya harus murni. Mereka seharusnya hanya beroperasi pada parameter mereka dan tidak boleh memiliki efek samping. Jika Anda memiliki fungsi murni, Anda dapat mempertimbangkan fungsi hanya dengan melihat satu fungsi. Jika fungsi Anda tidak murni, Anda harus mempertimbangkan keadaan komponen lain, dan itu menjadi jauh lebih sulit untuk dipikirkan.

Samuel
sumber
Ok, senang mendengar pendapat lain, tetapi tentang bau desain , saya memprogram masalah C yang diselesaikan dengan metode kecerdasan buatan dan saya cenderung menggunakan banyak fungsi yang hampir selalu menggunakan matriks, array, atau variabel yang sama (yang Saya lulus sebagai parameter ke fungsi), saya mengatakan ini karena saya tidak merasa bahwa saya dapat menempatkan variabel-variabel ini di dalam konsep umum / hal seperti struct atau gabungan jadi saya tidak akan tahu bagaimana membuat desain yang lebih baik, jadi itu sebabnya saya pikir penggunaan variabel global dalam hal ini bisa bernilai, tetapi kemungkinan besar saya salah.
OiciTrap
1
Itu tidak terdengar seperti masalah desain. Saya masih berpikir memberikan parameter ke fungsi adalah desain terbaik. Dalam sistem AI seperti yang Anda gambarkan, saya akan menemukan manfaat untuk menulis unit test untuk menguji bagian-bagian sistem, dan cara termudah untuk melakukannya adalah dengan parameter.
Samuel
96
Semakin banyak parameter membuat subrutin lebih sulit untuk dipahami, variabel global membuat seluruh program, yaitu semua subrutin lebih sulit untuk dipahami.
Jörg W Mittag
2
Saya memelihara basis kode di mana beberapa fungsi mengambil lebih dari selusin parameter. Ini pemborosan waktu yang sangat besar - setiap kali saya perlu memanggil fungsi saya harus membuka file itu di jendela lain sehingga saya tahu dalam urutan apa parameter harus ditentukan. Jika saya menggunakan IDE yang memberi saya sesuatu seperti intellisense atau jika saya menggunakan bahasa yang bernama parameter maka itu tidak akan terlalu buruk tetapi siapa yang bisa mengingat urutan selusin parameter untuk semua fungsi tersebut?
Jerry Jeremiah
6
Jawabannya benar dalam apa yang dikatakannya, namun tampaknya perlu OP salah paham tentang recommentations dalam "Kode Bersih" begitu saja. Saya yakin tidak ada rekomendasi untuk mengganti parameter fungsi oleh global dalam buku itu.
Doc Brown
68

Anda harus menghindari variabel global seperti wabah .

Saya tidak akan meletakkan batas keras untuk jumlah argumen (seperti 3 atau 4), tetapi Anda jangan ingin menjaga mereka untuk minimum, jika memungkinkan.

Gunakan structs (atau objek dalam C ++) untuk mengelompokkan variabel-variabel menjadi satu kesatuan dan meneruskannya (dengan referensi) ke fungsi. Biasanya suatu fungsi mendapat struktur atau objek (dengan beberapa hal berbeda di dalamnya) diteruskan ke sana bersama dengan beberapa parameter lain yang memberi tahu fungsi untuk melakukan sesuatu pada struct.

Untuk kode modular yang beraroma harum, bersih, cobalah untuk tetap berpegang pada prinsip tanggung jawab tunggal . Lakukan itu dengan struct Anda (atau objek), fungsi, dan file sumber. Jika Anda melakukan itu, jumlah parameter alami yang diteruskan ke suatu fungsi akan menjadi jelas.

robert bristow-johnson
sumber
5
Apa perbedaan utama antara melewati puluhan parameter yang disembunyikan di dalam struct dan meneruskannya secara eksplisit?
Ruslan
21
@Ruslan Cohesion.
abuzittin gillifirca
9
Dan Anda lebih cenderung untuk mengubah fungsi menjadi fungsi yang lebih kecil, karena Anda bisa meneruskan satu parameter ke sub-fungsi alih-alih puluhan parameter. Dan lebih sedikit risiko mencampur parameter jika Anda menggunakan argumen posisi.
Hans Olsson
8
Itu bagus, tetapi Anda harus memastikan koherensi dalam Structs - pastikan bahwa parameter yang dikelompokkan ke dalam Struct adalah 'terkait'. Anda mungkin menggunakan lebih dari satu Struct dalam beberapa keadaan.
Andrew Dodds
8
@abuzittingillifirca Anda tidak mendapatkan kohesi secara otomatis. Jika satu-satunya pembenaran untuk menempatkan parameter dalam sebuah struct adalah meneruskannya ke fungsi tertentu, maka kohesi mungkin ilusi.
sdenham
55

Kita berbicara tentang beban kognitif, bukan sintaksis. Jadi pertanyaannya adalah ... Apa adalah parameter dalam konteks ini?

Parameter adalah nilai yang mempengaruhi perilaku fungsi. Semakin banyak parameter, semakin banyak kemungkinan kombinasi nilai yang Anda dapatkan, semakin sulit penalaran tentang fungsi tersebut.

Dalam pengertian itu, variabel global yang digunakan fungsi adalah parameter. Mereka adalah parameter yang tidak muncul dalam tanda tangannya, yang memiliki masalah susunan konstruksi, kontrol akses, dan remanensi.

Kecuali jika parameter tersebut adalah apa yang disebut kekhawatiran lintas sektoral , yaitu beberapa kondisi seluruh program yang semuanya gunakan tetapi tidak ada yang berubah (misalnya objek logging), Anda tidak boleh mengganti parameter fungsi dengan variabel global. Mereka masih menjadi parameter, tetapi lebih buruk.

Quentin
sumber
11
Untuk Anda yang +1, baik itu toilet atau toilet mereka berbau sama. Pekerjaan yang bagus menunjukkan serigala dengan pakaian domba.
Jared Smith
1
1 untuk menyatakan bahwa banyak parm dan vars global buruk. Tetapi saya ingin mengklarifikasi sesuatu. Dalam sebagian besar bahasa, parameter primitif diteruskan oleh nilai secara default (Java), dan dalam bahasa lain Anda dapat mengirimkannya dengan nilai secara eksplisit (PL / SQL). Di sisi lain primitif global selalu diakses dengan referensi (bisa dikatakan). Jadi parameter, setidaknya dari tipe primitif, selalu lebih aman daripada variabel global. Meskipun tentu saja memiliki lebih dari dua atau tiga parameter adalah bau, dan memiliki dua belas parameter adalah bau besar yang harus di-refactored.
Tulains Córdova
4
Tentu saja, variabel global adalah parameter tersembunyi.
Bill K
+1 Menurut Anda, saya telah melihat simulasi MATLAB yang bergantung pada variabel global untuk meneruskan data. Hasilnya benar-benar tidak dapat dibaca karena sangat sulit untuk mengetahui variabel mana yang merupakan parameter untuk fungsi yang mana.
Cort Ammon
34

IMHO pertanyaan Anda didasarkan pada kesalahpahaman. Dalam "Kode Bersih", Bob Martin tidak menyarankan untuk mengganti parameter fungsi berulang oleh global, itu akan menjadi saran yang sangat mengerikan. Dia menyarankan untuk menggantinya dengan variabel anggota pribadi dari kelas fungsi. Dan dia juga mengusulkan kelas yang kecil dan kohesif (biasanya lebih kecil dari 600 baris kode yang Anda sebutkan), jadi variabel anggota ini jelas bukan global.

Jadi, ketika Anda memiliki pendapat dalam konteks dengan kurang dari 600 baris "menggunakan variabel global akan sia-sia" , maka Anda dengan sempurna membagikan pendapat Paman Bob. Tentu saja, masih bisa diperdebatkan jika "3 parameter pada maksimum" adalah angka ideal, dan jika aturan ini kadang-kadang menyebabkan terlalu banyak variabel anggota bahkan dalam kelas kecil. IMHO ini adalah trade-off, tidak ada aturan keras dan cepat di mana harus menarik garis.

Doc Brown
sumber
10
Saya tidak pernah mengerti mengapa seseorang lebih memilih untuk membuat kelas mereka stateful dengan memasukkan parameter menjadi konstruktor daripada hanya hidup dengan argumen yang sebenarnya. Ini selalu mengejutkan saya sebagai peningkatan kompleksitas yang luar biasa. (Sebuah contoh kehidupan nyata aku pernah melihat ini adalah objek koneksi database, yang membuat mencoba untuk melacak keadaan database melalui program hampir tidak mungkin bila dikombinasikan dengan injeksi ketergantungan.) Tapi mungkin Bersih Kode memiliki lebih untuk mengatakan pada yang tertentu subyek. Global, tentu saja, adalah pilihan yang bahkan lebih buruk dalam hal membuat keadaan menjadi jelas.
jpmc26
2
@ jpmc26: satu-satunya yang mendapat "peningkatan kerumitan enourmous" jika kelas menjadi terlalu besar dan mendapatkan terlalu banyak variabel anggota, sehingga hasilnya tidak kohesif lagi.
Doc Brown
4
Saya pikir respons itu mengabaikan kesulitan dalam mengelola negara (yang bahkan bisa berubah-ubah) yang tersebar di banyak kelas. Ketika suatu fungsi tidak hanya bergantung pada argumen tetapi juga pada bagaimana objek itu dibangun (atau bahkan dimodifikasi selama masa pakainya), memahami keadaan saat ini ketika Anda membuat panggilan tertentu menjadi lebih sulit. Anda sekarang harus melacak konstruksi objek lain , hanya untuk mengetahui apa yang akan dilakukan panggilan. Menambahkan variabel instan secara aktif meningkatkan jumlah keadaan program, kecuali jika Anda membuat objek dan langsung membuangnya?
jpmc26
3
@ jpmc26 Salah satu pola yang saya gunakan secara teratur ketika refactoring adalah bahwa konstruktor bertindak seperti mengatur konteks, kemudian argumen metode khusus untuk suatu tindakan. Objeknya tidak persis stateful, karena state yang dipegangnya tidak pernah berubah, tetapi memindahkan aksi-aksi umum tersebut ke dalam metode kontainer ini secara signifikan meningkatkan keterbacaan di mana ini digunakan (konteks hanya ditetapkan sekali, mirip dengan manajer konteks python), dan mengurangi duplikasi jika beberapa panggilan dilakukan ke metode objek.
Izkata
3
+1 Untuk mengatakan dengan jelas bahwa variabel anggota bukan variabel global. Banyak orang mengira begitu.
Tulains Córdova
34

Memiliki banyak parameter dianggap tidak diinginkan, tetapi mengubahnya menjadi bidang atau variabel global jauh lebih buruk karena tidak menyelesaikan masalah aktual tetapi menimbulkan masalah baru.

Memiliki banyak parameter tidak dengan sendirinya masalah, tetapi merupakan gejala bahwa Anda mungkin memiliki masalah. Pertimbangkan metode ini:

Graphics.PaintRectangle(left, top, length, height, red, green, blue, transparency);

Memiliki 7 parameter adalah tanda peringatan yang pasti. Masalah yang mendasarinya adalah parameter-parameter ini tidak independen tetapi termasuk dalam kelompok. leftdan topmilik bersama sebagai Position-struktur, lengthdan heightsebagai Sizestruktur, dan red, bluedan greensebagai Colorstruktur. Dan mungkin Colordan transparansi termasuk dalam Brushstruktur? Mungkin Positiondan Sizedimiliki bersama dalam suatu Rectanglestruktur, dalam hal mana kita bahkan dapat mempertimbangkan untuk mengubahnya menjadi Paintmetode pada Rectangleobjek? Jadi kita mungkin berakhir dengan:

Rectangle.Paint(brush);

Misi selesai! Tetapi yang penting adalah kita sebenarnya telah memperbaiki desain secara keseluruhan, dan pengurangan jumlah parameter adalah konsekuensi dari ini. Jika kami hanya mengurangi jumlah parameter tanpa menangani masalah mendasar, kami mungkin melakukan sesuatu seperti ini:

Graphics.left = something;
Graphics.top = something;
Graphics.length = something;
...etc
Graphics.PaintRectangle();

Di sini kami telah mencapai pengurangan yang sama dalam jumlah parameter, tetapi kami sebenarnya telah memperburuk desain .

Intinya: Untuk saran dan aturan pemrograman apa pun, sangat penting untuk memahami alasan yang mendasarinya.

JacquesB
sumber
4
+1 jawaban yang bagus, konstruktif, dapat dimengerti, dan tidak teoretis.
AnoE
1
Belum lagi, apa yang Anda "kuadratkan" lakukan memiliki atribut panjang DAN tinggi. :)
Wildcard
1
1 untuk mengakui bahwa cara ketiga yang jelas tersirat oleh beberapa jawaban (mis. Banyak tugas untuk beberapa struktur / objek sebelum pemanggilan fungsi) tidak lebih baik.
benxyzzy
@ Kartu Memori: Terima kasih, ubah menjadi "persegi panjang" untuk menghindari masalah yang membingungkan!
JacquesB
7

apakah layak menggunakan variabel global untuk mengurangi jumlah parameter fungsi atau tidak?

Tidak

Saya membaca bab-bab pertama buku ini

Apakah Anda membaca sisa buku ini?

Global hanyalah parameter tersembunyi. Mereka menyebabkan rasa sakit yang berbeda. Tapi masih sakit. Berhentilah memikirkan cara untuk menyiasati aturan ini. Pikirkan bagaimana cara mengikutinya.

Apa itu parameter?

Itu barang. Dalam kotak berlabel baik. Mengapa penting berapa banyak kotak yang Anda miliki ketika Anda bisa memasukkan barang apa pun di dalamnya?

Ini adalah biaya pengiriman dan penanganan.

Move(1, 2, 3, 4)

Katakan padaku kamu bisa membacanya. Ayo, coba.

Move(PointA, PointB)

Itu sebabnya.

Trik itu disebut memperkenalkan parameter objek .

Dan ya itu hanya tipuan jika yang Anda lakukan hanyalah menghitung parameter. Yang harus Anda hitung adalah IDEAS! Abstraksi! Berapa banyak yang membuat saya berpikir sekaligus? Tetap sederhana.

Sekarang ini jumlah yang sama:

Move(xyx, y)

OW! Mengerikan! Apa yang salah di sini?

Tidak cukup membatasi jumlah ide. Itu harus ide yang jelas. Apa itu xyx?

Sekarang ini masih lemah. Apa cara yang lebih kuat untuk memikirkan hal ini?

Fungsinya harus kecil. Tidak lebih kecil dari itu.

Paman Bob

Move(PointB)

Mengapa membuat fungsi melakukan lebih dari yang sebenarnya perlu dilakukan? Prinsip tanggung jawab tunggal tidak hanya untuk kelas. Serius, ada baiknya mengubah seluruh arsitektur hanya untuk menghentikan satu fungsi dari berubah menjadi mimpi buruk yang berlebihan dengan 10 parameter terkait terkadang beberapa di antaranya tidak dapat digunakan dengan yang lain.

Saya telah melihat kode di mana jumlah baris paling umum dalam suatu fungsi adalah 1. Serius. Saya tidak mengatakan Anda harus menulis seperti itu tetapi sheesh, jangan bilang global adalah HANYA cara Anda dapat mematuhi aturan ini. Berhentilah mencoba keluar dari refactoring fungsi itu dengan benar. Kamu tahu kamu bisa. Mungkin terpecah menjadi beberapa fungsi. Ini mungkin benar-benar berubah menjadi beberapa objek. Sial, Anda bahkan dapat memecah sebagiannya menjadi aplikasi yang sama sekali berbeda.

Buku ini tidak memberitahu Anda untuk menghitung parameter Anda. Ia memberi tahu Anda untuk memperhatikan rasa sakit yang Anda sebabkan. Apa pun yang memperbaiki rasa sakit akan memperbaiki masalahnya. Berhati-hatilah saat Anda hanya memperdagangkan satu rasa sakit untuk yang lain.

candied_orange
sumber
3
"Apakah kamu membaca sisa buku itu?" Pertanyaan Anda dijawab dalam 8 kata pertama dari posting saya ...
OiciTrap
Saya sepenuhnya setuju - intinya adalah untuk menguraikan masalah menjadi potongan-potongan kecil. Objek benar-benar dapat membantu mengatur potongan-potongan ini dan mengelompokkannya, mereka juga memungkinkan satu unit konseptual untuk dilewatkan sebagai parameter daripada sekelompok potongan yang tidak terhubung. Saya menjadi gelisah ketika saya melihat metode dengan lebih dari 3 parameter. 5 adalah indikasi bahwa desain saya telah hancur dan saya membutuhkan putaran refactoring lagi. Cara terbaik yang saya temukan untuk menyelesaikan masalah desain seperti penghitungan parameter adalah dengan hanya memperbaiki hal-hal menjadi unit yang lebih kecil, lebih sederhana (kelas / metode).
Bill K
2
Nada dari jawaban ini dapat ditingkatkan. Bunyinya sangat mendadak dan keras. Misalnya: "Katakan, Anda bisa membacanya. Ayo, coba." tampak sangat agresif dan dapat ditulis ulang sebagai "Dari dua panggilan fungsi di atas / di bawah, yang mana yang lebih mudah dibaca?" Anda harus mencoba menyampaikan maksudnya tanpa agresi. OP hanya berusaha belajar.
Kyle A
Jangan lupa OP juga berusaha untuk tetap terjaga.
candied_orange
4

Saya tidak akan pernah menggunakan variabel global untuk mengurangi parameter. Alasannya adalah bahwa variabel global dapat diubah oleh fungsi / perintah apa pun, oleh karena itu membuat input fungsi tidak dapat diandalkan dan rentan terhadap nilai yang berada di luar ruang lingkup yang dapat ditangani oleh fungsi tersebut. Bagaimana jika variabel diubah selama eksekusi fungsi dan separuh fungsi memiliki nilai yang berbeda dari setengah lainnya?

Melewati parameter di sisi lain, membatasi ruang lingkup variabel hanya untuk fungsinya sendiri sehingga hanya fungsi yang dapat mengubah parameter setelah dipanggil.

Jika Anda perlu meneruskan variabel global alih-alih parameter, lebih baik untuk mendesain ulang kode.

Hanya dua sen saya.

Dimos
sumber
"Saya tidak akan pernah menggunakan variabel global untuk mengurangi parameter" sepenuhnya setuju. Ini menciptakan kopling yang tidak perlu.
bytedev
2

Saya dengan Paman Bob dalam hal ini dan setuju bahwa lebih dari 3 params adalah sesuatu yang harus dihindari (saya sangat jarang menggunakan lebih dari 3 params dalam suatu fungsi). Memiliki banyak params pada satu fungsi menciptakan masalah pemeliharaan yang lebih besar dan mungkin bau bahwa fungsi Anda melakukan terlalu banyak / memiliki tanggung jawab terlalu banyak.

Jika Anda menggunakan lebih dari 3 dalam suatu metode dalam bahasa OO maka Anda harus mempertimbangkan apakah params tidak terkait satu sama lain dalam beberapa cara dan karena itu Anda harus benar-benar melewati sebuah objek saja?

Juga, jika Anda membuat lebih banyak fungsi (lebih kecil) Anda juga akan melihat bahwa fungsi cenderung lebih sering memiliki 3 params atau kurang. Ekstrak fungsi / metode adalah teman Anda :-).

Jangan gunakan variabel global sebagai cara untuk mendapatkan lebih banyak params! Itu adalah menukar satu praktik buruk dengan yang lebih buruk!

bytedev
sumber
1

Alternatif yang valid untuk banyak parameter fungsi adalah dengan memperkenalkan objek parameter . Ini berguna jika Anda memiliki metode yang terdiri yang melewati (hampir) semua parameternya ke sekelompok metode lain.

Dalam kasus sederhana ini adalah DTO sederhana yang tidak memiliki apa pun kecuali parameter lama sebagai properti.

Timothy Truckle
sumber
1

Menggunakan variabel global sepertinya selalu merupakan cara yang mudah untuk kode (terutama dalam program kecil), tetapi itu akan membuat kode Anda sulit diperluas.

Ya, Anda bisa mengurangi jumlah parameter dalam suatu fungsi dengan menggunakan array untuk mengikat parameter dalam satu entitas.

function <functionname>(var1,var2,var3,var4.....var(n)){}

Fungsi di atas akan diedit dan diubah menjadi [menggunakan array asosiatif] -

data=array(var1->var1,
           var2->var2
           var3->var3..
           .....
           ); // data is an associative array

function <functionname>(data)

Saya setuju dengan jawaban robert bristow-johnson : Anda bahkan dapat menggunakan struct untuk mengikat data dalam satu entitas.

Narender Parmar
sumber
1

Mengambil contoh dari PHP 4, lihat tanda tangan fungsi untuk mktime():

  • int mktime ([ int $hour = date("H") [, int $minute = date("i") [, int $second = date("s") [, int $month = date("n") [, int $day = date("j") [, int $year = date("Y") [, int $is_dst = -1 ]]]]]]] )

Tidakkah Anda merasa itu membingungkan? Fungsi ini disebut "buat waktu" tetapi membutuhkan parameter hari, bulan dan tahun serta tiga parameter waktu. Seberapa mudah untuk mengingat urutan mereka masuk? Bagaimana jika kamu melihat mktime(1, 2, 3, 4, 5, 2246);? Bisakah Anda memahami itu tanpa harus merujuk ke hal lain? Apakah 2246ditafsirkan sebagai waktu 24 jam "22:46"? Apa arti dari parameter lainnya? Akan lebih baik sebagai objek.

Pindah ke PHP 5, sekarang ada objek DateTime. Di antara metodenya ada dua yang disebut setDate()dan setTime(). Tanda tangan mereka adalah sebagai berikut:

  • public DateTime setDate ( int $year , int $month , int $day )
  • public DateTime setTime ( int $hour , int $minute [, int $second = 0 ] )

Anda masih harus ingat bahwa urutan parameternya berubah dari yang terbesar ke yang terkecil, tetapi ini merupakan peningkatan besar. Perhatikan bahwa tidak ada metode tunggal yang memungkinkan Anda untuk mengatur keenam parameter sekaligus. Anda harus membuat dua panggilan terpisah untuk melakukan ini.

Apa yang Paman Bob bicarakan adalah menghindari memiliki struktur yang datar. Parameter terkait harus dikelompokkan bersama menjadi objek, dan jika Anda memiliki lebih dari tiga parameter, sangat mungkin Anda punya objek pseudo di sana, yang memberi Anda peluang untuk membuat objek yang sesuai untuk pemisahan yang lebih besar. Meskipun PHP tidak memiliki kelas Datedan terpisah Time, Anda dapat mempertimbangkan yang DateTimebenar - benar berisi Dateobjek dan Timeobjek.

Anda mungkin memiliki struktur berikut:

<?php
$my_date = new Date;
$my_date->setDay(5);
$my_date->setMonth(4);
$my_date->setYear(2246);

$my_time = new Time;
$my_time->setHour(1);
$my_time->setMinute(2);
$my_time->setSecond(3);

$my_date_time = new DateTime;
$my_date_time->setTime($my_time);
$my_date_time->setDate($my_date);
?>

Apakah wajib untuk menetapkan dua atau tiga parameter setiap kali? Jika Anda ingin mengubah jam atau hari, sekarang mudah untuk melakukannya. Ya, objek perlu divalidasi untuk memastikan setiap parameter berfungsi dengan yang lain, tapi itu yang terjadi sebelumnya.

Yang paling penting adalah, apakah lebih mudah dipahami, dan karenanya dipertahankan? Blok kode di bagian bawah lebih besar dari satu mktime()fungsi, tapi saya berpendapat itu jauh lebih mudah dipahami; bahkan non-programmer tidak akan mengalami banyak kesulitan dalam mengerjakan apa yang dikerjakannya. Tujuannya tidak selalu kode lebih pendek atau kode pintar, tetapi kode lebih dapat dipertahankan.

Oh, dan jangan gunakan global!

CJ Dennis
sumber
1

Banyak jawaban bagus di sini namun sebagian besar tidak membahas maksudnya. Mengapa ini aturan praktis? Ini tentang ruang lingkup, ini tentang dependensi dan ini tentang pemodelan yang tepat.

Global untuk argumen lebih buruk karena sepertinya Anda membuatnya lebih sederhana tetapi sebenarnya Anda hanya menyembunyikan kerumitannya. Anda tidak melihatnya lagi dalam prototipe tetapi Anda masih harus menyadarinya (yang sulit karena tidak ada untuk Anda lihat lagi) dan mendapatkan kepala Anda di sekitar logika fungsi tidak akan membantu Anda karena mungkin ada menjadi logika tersembunyi lainnya yang mengganggu di belakang Anda. Cakupan Anda meliputi semua tempat dan Anda memperkenalkan ketergantungan pada apa pun karena apa pun sekarang dapat mengacaukan variabel Anda. Tidak baik.

Hal utama yang harus dipertahankan untuk suatu fungsi adalah Anda dapat memahami apa fungsinya dengan melihat prototipe dan panggilan. Jadi namanya harus jelas dan tidak ambigu. Tetapi juga, semakin banyak argumen semakin sulit untuk memahami apa yang dilakukannya. Ini memperluas cakupan di kepala Anda, terlalu banyak hal yang terjadi, inilah mengapa Anda ingin membatasi jumlahnya. Itu penting argumen apa yang Anda hadapi, beberapa lebih buruk dari yang lain. Boolean opsional tambahan yang memungkinkan pemrosesan tidak sensitif pada kasus tidak membuat fungsi lebih sulit untuk dipahami sehingga Anda tidak ingin membuat masalah besar tentang hal itu. Sebagai catatan, enum membuat argumen yang lebih baik daripada boolean karena makna enum jelas dalam panggilan.

Masalah yang biasa terjadi bukanlah Anda menulis fungsi baru dengan sejumlah besar argumen, Anda akan mulai dengan hanya beberapa ketika Anda belum menyadari betapa rumitnya masalah yang Anda selesaikan sebenarnya. Saat program Anda berkembang, daftar argumen secara bertahap cenderung semakin panjang. Setelah model menetapkan dalam pikiran Anda, Anda ingin menyimpannya karena itu adalah referensi aman yang Anda tahu. Tapi kalau dipikir-pikir modelnya mungkin tidak terlalu bagus. Anda melewatkan satu langkah atau terlalu dalam logika dan Anda gagal mengenali satu atau dua entitas. "Oke ... saya bisa memulai lagi dan menghabiskan satu atau dua hari refactoring kode saya atau ... saya bisa menambahkan argumen ini sehingga saya bisa membuatnya melakukan hal yang benar dan selesai dengan itu. Untuk sekarang. Untuk skenario ini Untuk menghilangkan bug ini dari piringan saya sehingga saya bisa memindahkan catatan tempel ke selesai. "

Semakin sering Anda pergi dengan solusi kedua semakin mahal perawatan lanjutan akan terjadi dan semakin sulit dan tidak menarik akan menjadi refactor.

Tidak ada solusi pelat ketel untuk mengurangi jumlah argumen dalam fungsi yang ada. Mengelompokkan mereka menjadi senyawa tidak benar-benar membuat segalanya lebih mudah, itu hanyalah cara lain untuk menyeka kompleksitas di bawah karpet. Melakukannya dengan benar melibatkan melihat seluruh tumpukan panggilan lagi dan mengenali apa yang hilang atau telah dilakukan salah.

Martin Maat
sumber
0

Beberapa kali saya telah menemukan bahwa pengelompokan banyak parameter yang dikirim bersama memperbaiki keadaan.

  • Ini memaksa Anda untuk memberikan nama yang bagus pada konsep konsep yang digunakan bersama. Jika Anda menggunakan parameter-parameter itu bersama-sama, bisa jadi mereka memiliki hubungan (atau Anda tidak boleh menggunakannya bersama-sama).

  • Setelah dengan objek saya biasanya menemukan bahwa beberapa funtionality dapat dipindahkan bahwa objek ini tampaknya stuypid. Biasanya mudah untuk menguji dan dengan kohesi yang hebat dan kopling yang rendah membuat hal itu menjadi lebih baik.

  • Lain kali saya perlu menambahkan parameter baru saya punya tempat yang bagus untuk memasukkannya tanpa mengubah tanda tangan banyak metode.

Jadi itu mungkin tidak bekerja 100% dari waktu tetapi tanyakan pada diri sendiri apakah daftar parameter ini harus dikelompokkan dalam suatu objek. Dan tolong. Jangan gunakan kelas yang tidak diketik seperti Tuple untuk menghindari membuat objek. Anda menggunakan pemrograman berorientasi objek, tidak keberatan membuat lebih banyak objek jika Anda membutuhkannya.

Borjab
sumber
0

Dengan segala hormat, saya cukup yakin Anda benar-benar melewatkan titik memiliki sejumlah kecil parameter dalam suatu fungsi.

Idenya adalah bahwa otak hanya dapat menyimpan begitu banyak "informasi aktif" pada satu waktu, dan jika Anda memiliki n parameter dalam suatu fungsi, Anda memiliki n lebih banyak "informasi aktif" yang perlu ada di otak Anda dengan mudah dan akurat. pahami apa yang dilakukan oleh potongan kode (Steve McConnell, dalam Code Complete (buku yang jauh lebih baik, IMO), mengatakan sesuatu yang serupa tentang 7 variabel dalam tubuh metode: jarang kita mencapai itu, tetapi lebih lagi dan Anda kehilangan kemampuan menjaga semuanya tetap lurus di kepala Anda).

Inti dari sejumlah variabel yang rendah adalah untuk dapat menjaga persyaratan kognitif untuk bekerja dengan kode ini kecil, sehingga Anda dapat bekerja dengannya (atau membacanya) lebih efektif. Penyebab utama dari hal ini adalah kode yang difaktorkan dengan baik akan cenderung memiliki parameter yang semakin sedikit (mis., Kode dengan faktor buruk cenderung untuk mengelompokkan banyak barang menjadi berantakan).

Dengan melewatkan objek alih-alih nilai, mungkin Anda mendapatkan tingkat abstraksi untuk otak Anda karena sekarang perlu disadari ya, saya punya SearchContext untuk bekerja di sini alih-alih memikirkan 15 properti yang mungkin berada dalam konteks pencarian itu.

Dengan mencoba menggunakan variabel Global, Anda telah sepenuhnya pergi ke seluruh arah yang salah. Sekarang Anda tidak hanya tidak menyelesaikan masalah karena memiliki terlalu banyak parameter untuk suatu fungsi, Anda telah mengambil masalah itu dan melemparkannya ke dalam masalah yang jauh lebih baik yang sekarang harus Anda bawa ke dalam pikiran Anda!

Sekarang alih-alih bekerja hanya pada tingkat fungsi, Anda juga harus mempertimbangkan lingkup global proyek Anda (ya ampun, betapa mengerikan! Saya ngeri ...). Anda bahkan tidak memiliki semua informasi di depan Anda dalam fungsi (omong kosong, apa itu nama variabel global?) (Saya harap ini belum diubah oleh sesuatu yang lain sejak saya memanggil fungsi ini).

Variabel yang dicakup secara global adalah salah satu hal yang paling buruk untuk dilihat dalam suatu proyek (besar atau kecil). Mereka menunjukkan ketidakmampuan untuk manajemen ruang lingkup yang tepat, yang merupakan keterampilan yang sangat mendasar untuk pemrograman. Mereka. Adalah. Jahat.

Dengan memindahkan parameter dari fungsi Anda dan menempatkannya ke dalam global, Anda telah menembak diri sendiri di foor (atau kaki, atau wajah). Dan Tuhan melarang Anda memutuskan bahwa hei, saya dapat menggunakan kembali global ini untuk sesuatu yang lain ... pikiran saya gemetar pada pikiran itu.

Keseluruhan yang ideal adalah menjaga hal-hal mudah dikelola, dan variabel global TIDAK akan melakukan itu. Saya akan mengatakan bahwa itu adalah salah satu hal terburuk yang dapat Anda lakukan untuk pergi ke arah yang berlawanan.

Jachach
sumber
-1

Saya telah menemukan pendekatan yang sangat efektif (dalam JavaScript) untuk meminimalkan gesekan antar antarmuka: Gunakan antarmuka yang seragam untuk semua modul , khususnya: fungsi param tunggal.

Saat Anda membutuhkan banyak parameter: Gunakan satu Objek / Hash atau Array.

Bersabarlah, aku berjanji aku tidak trolling ...

Sebelum Anda mengatakan "apa gunanya fungsi param tunggal?" Atau "Apakah ada perbedaan antara fungsi 1 Array dan multi arg?"

Baiklah. Ini mungkin secara visual halus, tetapi perbedaannya berlipat ganda - Saya mengeksplorasi banyak manfaat di sini

Rupanya beberapa orang menganggap 3 adalah # argumen yang tepat. Beberapa orang berpikir itu 2. Nah, itu masih menimbulkan pertanyaan, "param mana yang ada di arg [0]?" Alih-alih memilih opsi yang membatasi antarmuka dengan deklarasi yang lebih kaku.

Saya kira saya berpendapat untuk posisi yang lebih radikal: jangan mengandalkan argumen posisi. Saya hanya merasa itu rapuh dan mengarah ke argumen tentang posisi argumen sialan itu. Lewati dan teruskan ke pertarungan yang tak terelakkan tentang nama fungsi dan variabel. 😉

Serius meskipun, setelah penamaan menetap, mudah-mudahan Anda berakhir dengan kode seperti berikut, yang agak mendokumentasikan diri, tidak sensitif terhadap posisi, dan memungkinkan perubahan param di masa depan untuk ditangani di dalam ke fungsi:

function sendMessage({toUser, fromUser, subject, body}) { }

// And call the method like so:
sendMessage({toUser: this.parentUser, fromUser: this.currentUser, subject: ‘Example Alert’})

Dan Levy
sumber
6
Memalsukan argumen bernama tidak benar-benar melewati hanya satu argumen.
JDługosz
Mengapa "berpura-pura" jika saya mencapai tujuan yang saya tetapkan? Saya menempatkan prioritas yang lebih tinggi pada argumen yang disebutkan. Karena argumen posisi tidak jelas untuk memanggil kode, dan dengan # fungsi yang dinamai dev harus dihafalkan, tidak membantu mengingat params mana dan mana yang opsional. ... Pada akhirnya, Anda akan ingin menambahkan param yang diperlukan setelah opsional, semoga berhasil mendokumentasikan & memutakhirkan rumah kartu tersebut.
Dan Levy
2
Param yang dinamai juga merupakan trik pembelajaran penguatan - manusia lebih mementingkan kumpulan kata-kata.
Dan Levy