Apa praktik terbaik pada pemesanan parameter dalam suatu fungsi?

52

Terkadang (jarang), tampaknya menciptakan fungsi yang membutuhkan jumlah parameter yang layak adalah rute terbaik. Namun, ketika saya melakukannya, saya merasa seperti saya sering memilih urutan parameter secara acak. Saya biasanya menggunakan "urutan kepentingan", dengan parameter terpenting terlebih dahulu.

Apakah ada cara yang lebih baik untuk melakukan ini? Apakah ada cara "praktik terbaik" memesan parameter yang meningkatkan kejelasan?

Casey Patton
sumber
5
Parameter bernama membuat ini kurang dari masalah. Python membawanya ke ekstrem, lihat ke dalamnya. Contoh yang baik adalah di C # - banyak cara untuk menelepon MessageBox.Show. Lihat itu juga.
Pekerjaan
8
Dalam Haskell, kemungkinan kegunaan aplikasi fungsi parsial biasanya menyarankan pemesanan argumen alami.
tdammers
Apa yang Anda anggap jumlah parameter yang layak?
Chris
Saya berpikir> 2. Meskipun saya kira pemesanan berlaku untuk 2 parameter semua sama.
Casey Patton
3
@tdammers ini juga berlaku untuk bahasa apa pun yang memiliki dukungan langsung untuk currying
jk.

Jawaban:

55

Secara umum: gunakan itu .

Tulis tes untuk fungsi Anda, tes dunia nyata.
Sesuatu yang sebenarnya ingin Anda lakukan dengan fungsi itu .

Dan lihat dalam urutan apa Anda meletakkannya.

Kecuali Anda sudah memiliki (atau mengetahui) beberapa fungsi yang melakukan hal serupa.
Dalam hal itu: sesuaikan dengan apa yang sudah mereka lakukan, setidaknya untuk argumen pertama.

mis. Apakah mereka semua mengambil dokumen / objek / file-pointer / serangkaian-nilai / koordinat sebagai argumen pertama? Demi tuhan, sesuaikan dengan argumen itu .

Hindari membingungkan rekan kerja dan masa depan Anda .

ZJR
sumber
12
"Hindari membingungkan ... diri masa depan Anda" terdengar seperti filosofi yang baik secara umum.
Jeanne Pindar
28

Saya biasanya mengikuti aturan ini, meskipun tidak selalu dengan prioritas yang sama. Saya kira ini adalah proses pemikiran otomatis sekarang, dan saya tidak terlalu memikirkannya, kecuali untuk desain API publik .

Saluran Seleksi

  1. Semantik
  2. Pentingnya / Relevansi
  3. Frekuensi Penggunaan
  4. Kekhawatiran I / O

1. Semantik Pertama

Khususnya dalam OOP, pilih parameter berdasarkan signifikansi semantik mereka untuk tindakan atau pesan. Tanda tangan dari metode yang dinamai dengan parameter yang dinamai harus:

  • merasa wajar untuk menelepon,
  • menjadi deskriptif diri dalam hal niat dan perilaku.

(Untuk alasan ini, terkadang menggunakan jenis atau alias khusus alih-alih primitif dapat meningkatkan ekspresi tanda tangan Anda.)

2. Kemudian Pentingnya

Parameter paling "signifikan" adalah yang utama (atau selanjutnya ...)

3. Kemudian Frekuensi

Frekuensi juga penting, terutama dalam bahasa di mana Anda tidak memiliki nama parameter tetapi dapat memiliki nilai default pada parameter posisi. Itu menyiratkan bahwa urutan parameter tidak bervariasi, dan yang jelas Anda tidak dapat mengatur parameter N + 1 jika Anda ingin memaksakan nilai default dari parameter Nth (kecuali jika bahasa Anda memiliki konsep parameter place-holder) ).

Kabar baiknya bagi Anda adalah bahwa biasanya, frekuensi berkaitan dengan kepentingan, sehingga sejalan dengan poin sebelumnya. Dan mungkin terserah Anda untuk membuat API Anda agar memiliki semantik yang sesuai.

4. Jangan Lupa I / O

jika metode / fungsi Anda mengambil beberapa input dan menghasilkan output, dan yang terakhir tidak boleh "dikembalikan" (melalui pernyataan pengembalian) atau "dilempar" (menggunakan sistem pengecualian), maka Anda memiliki opsi untuk lulus nilai kembali ke pemanggil menggunakan parameter lain Anda (atau parameter input). Itu berhubungan dengan semantik, dan dalam banyak kasus masuk akal untuk memiliki parameter pertama yang menentukan output, dan parameter terakhir menerima output.

Selain itu, pendekatan lain untuk memiliki lebih sedikit parameter dan memaksimalkan semantik akan menggunakan pendekatan fungsional, atau untuk menentukan pola Builder , sehingga Anda dapat dengan jelas menumpuk input Anda, menentukan output Anda, dan mengambilnya ketika diperlukan.

(Perhatikan saya tidak menyebutkan variabel global, karena mengapa Anda akan menggunakannya, kan?)


Beberapa hal yang perlu dipertimbangkan

  • Kegunaan

    Sebagian besar di atas akan muncul secara alami jika Anda mengikuti saran ZJR : Gunakan!

  • Pertimbangkan Refactoring

    Jika Anda khawatir tentang pemesanan parameter, mungkin kekhawatiran ini menemukan akarnya di atas dan bahwa API Anda dirancang dengan buruk. Jika Anda memiliki terlalu banyak parameter, sesuatu kemungkinan besar dapat menjadi komponen / modularized dan refactored .

  • Pertimbangkan Kinerja

    Perlu diingat bahwa implementasi beberapa bahasa akan menimbulkan dampak yang sangat penting pada manajemen memori runtime Anda saat menggunakan parameter. Karenanya alasan mengapa banyak buku gaya bahasa merekomendasikan untuk membuat daftar parameter sederhana dan singkat . Pada 4 parameter maks, misalnya. Saya meninggalkannya sebagai latihan bagi Anda untuk mencari tahu alasannya.

  • Jawaban Bevan dan penyebutan rekomendasi Clean Code juga sangat relevan!

haylem
sumber
18

Dengan hormat saya sampaikan bahwa khawatir tentang pemesanan parameter mengkhawatirkan hal yang salah.

Dalam buku Paman Bob " Kode Bersih " dia menganjurkan, secara persuasif, bahwa metode tidak boleh memiliki lebih dari dua argumen - dan sebagian besar seharusnya hanya memiliki satu, jika ada. Ketika hal ini terjadi, pemesanan jelas atau tidak penting.

Namun tidak sempurna, saya mencoba mengikuti saran Paman Bob - dan itu meningkatkan kode saya.

Dalam kasus yang jarang terjadi di mana metode tampaknya membutuhkan lebih banyak informasi, memperkenalkan objek parameter adalah ide yang bagus. Biasanya, saya menemukan ini adalah langkah pertama menuju penemuan konsep (objek) baru yang merupakan kunci dari algoritma saya.

Bevan
sumber
Saya pasti setuju dengan Anda! Pernyataan pertama saya bertujuan untuk memahami bahwa ini bukan hal yang khas bagi saya, haha. Tetapi dalam kasus yang saya temukan saya benar-benar harus melewati beberapa parameter dan itu tidak layak untuk refactor seluruh program, saya bertanya-tanya tentang pemesanan.
Casey Patton
3
batuk PHP batuk . Maaf - Anda mengatakan sesuatu tentang tidak khawatir tentang urutan parameter?
Craige
Tidakkah Anda kemudian hanya memiliki konstruktor untuk objek parameter Anda yang mengambil banyak argumen?
Detly
Tidak - karena objek parameter dapat "dibangun" di atas beberapa pernyataan dengan cara yang lebih mudah dibaca.
Bevan
2
@Bevan: ini sangat bisa diperdebatkan. Membangun objek dengan cara ini berarti mereka tidak bisa berubah lagi; menjaga benda-benda Anda tidak berubah kapan pun dimungkinkan, tetapi merupakan cara hebat lainnya untuk meningkatkan pemeliharaan.
tdammers
10

Saya mencoba untuk menempatkan parameter IN pertama, parameter OUT kedua. Ada juga beberapa pemesanan alami, misalnya createPoint(double x, double y)sangat disukai createPoint(double y, double x).

quant_dev
sumber
5
Terkadang yang sebaliknya lebih baik, misalnya, ketika selalu ada hanya satu argumen OUT dan sejumlah variabel dalam argumen, seperti dalam addAllTo(target, something1, something2).
maaartinus
Meskipun saya mengikuti aturan yang sama, saya mencoba untuk menghindari parameter OUT kapan pun memungkinkan, dan sebagian besar programmer juga. Jadi jumlah fungsi di mana rekomendasi ini sebenarnya membantu OP harus agak kecil.
Doc Brown
7
@DocBrown Anda benar-benar tidak boleh mencoba untuk menghindari programmer yang baik, mereka dapat bermanfaat untuk dimiliki
RyanfaeScotland
@RyanfaeScotland: sial, saya harus membaca komentar saya dua kali sebelum mempostingnya (atau setidaknya dalam lima menit saya bisa mengubahnya) ;-)
Doc Brown
6

Saya belum pernah melihat "praktik terbaik" yang terdokumentasi mengenai topik khusus ini, tetapi standar pribadi saya adalah mencantumkannya dalam urutan di mana mereka akan muncul dalam metode yang sedang mereka gunakan atau jika metode tersebut lebih dari satu pass-through ke lapisan data saya akan daftar mereka dalam urutan mereka akan muncul dalam skema db atau metode lapisan data.

Juga, ketika ada beberapa kelebihan metode, saya perhatikan bahwa cara yang umum adalah mendaftarnya dimulai dengan parameter yang umum untuk semua (atau sebagian besar) metode dengan setiap metode yang berbeda ditambahkan ke akhir untuk setiap metode kelebihan seperti :

void func1(string param) { }
void func2(string param, int param2) { }
void func3(string param, string param3) { }
void func3(string param, int param2, string param3) { }
Joel Etherton
sumber
6

Urutan: input, output, parameter opsional.

Jonathan Khoo
sumber
3

Saya sering mengikuti konvensi C / C ++ menempatkan constparameter terlebih dahulu (yaitu, parameter yang Anda lewati dengan nilai), dan kemudian yang Anda lewati dengan referensi. Ini mungkin bukan metode yang tepat untuk fungsi panggilan tetapi, jika Anda tertarik pada bagaimana masing-masing kompiler menangani parameter, lihat tautan berikut untuk aturan yang mengatur dan / atau urutan parameter didorong ke stack.

http://msdn.microsoft.com/en-us/library/zthk2dkh%28v=vs.80%29.aspx

http://en.wikipedia.org/wiki/Calling_convention

Tagihan
sumber
Tautan lain yang mungkin menarik bagi Anda adalah msdn.microsoft.com/en-us/library/984x0h58%28v=vs.71%29.aspx Untuk fungsi rekursif, lihat tautan berikut. publications.gbdirect.co.uk/c_book/chapter4/… Bukannya saya lupa tetapi, sebagai pengguna baru saya tidak dapat memposting komentar yang memiliki lebih dari dua tautan .... sungguh menyebalkan!
Bill
1

Saya biasanya hanya pergi dengan memesan parameter "apa yang terlihat kurang cyprtic". Semakin sedikit kali saya harus pergi ke metode / definisi fungsi semakin baik. Dan itu bagus untuk menamai parameter yang deskriptif untuk apa mereka digunakan, dengan cara itu ketika tooltip kecil muncul (VS) maka membuatnya lebih mudah.

Jika Anda memiliki garis dan garis parameter, Anda mungkin ingin mempertimbangkan desain yang berbeda. Mundur dan lihat bagaimana Anda dapat memecahnya menjadi lebih banyak fungsi / metode. Hanya sebuah ide, tetapi ketika saya memiliki selusin parameter dalam fungsi saya, itu hampir selalu bukan masalah parameter, tetapi masalah desain.


sumber
2
"cyprtic": cara yang bagus untuk menjelaskan maksudnya.
Bevan
2
Anda belum pernah salah ketik sebelumnya, @Bevan?
1
Saya memiliki kesalahan ketik sepanjang waktu - menulis cyprtic sangat bagus saya pikir itu sengaja . Harap ubah kembali, ini membantu untuk menegaskan maksud Anda, meskipun itu kecelakaan.
Bevan
1
@ Brian, haha ​​oke saya mengerti apa yang Anda katakan. Poin bagus! Ini berubah kembali =)
1

Terkadang (jarang), tampaknya menciptakan fungsi yang membutuhkan jumlah parameter yang layak adalah rute terbaik.

Menggunakan beberapa parameter seringkali merupakan indikator yang jelas, bahwa Anda melanggar SRP dalam metode ini. Suatu metode, yang membutuhkan banyak parameter tidak mungkin hanya melakukan satu hal. Pengecualian dapat berupa fungsi matematika atau metode konfigurasi, di mana memang diperlukan beberapa parameter . Saya akan menghindari beberapa parameter karena iblis menghindari air suci. Semakin banyak parameter yang Anda gunakan dalam suatu metode, semakin tinggi peluangnya, bahwa metode itu terlalu rumit; semakin rumit berarti: lebih sulit untuk dipertahankan dan itu kurang diinginkan.

Namun, ketika saya melakukannya, saya merasa seperti saya sering memilih urutan parameter secara acak. Saya biasanya menggunakan "urutan kepentingan", dengan parameter terpenting terlebih dahulu.

Pada prinsipnya Anda memilih secara acak . Tentu saja Anda mungkin berpikir paramter A lebih relevan daripada parameter B ; tapi itu mungkin bukan kasus untuk pengguna API Anda, yang menganggap B adalah parameter yang paling relevan. Jadi, bahkan jika Anda penuh perhatian dalam memilih pemesanan - bagi orang lain itu bisa tampak acak .

Apakah ada cara yang lebih baik untuk melakukan ini? Apakah ada cara "praktik terbaik" memesan parameter yang meningkatkan kejelasan?

Ada beberapa jalan keluar:

a) Kasus sepele: Jangan gunakan lebih dari satu parameter.

b) Karena Anda tidak menentukan, bahasa apa yang Anda pilih, ada kemungkinan, bahwa Anda memilih bahasa dengan parameter bernama . Ini adalah gula sintaksis yang bagus yang memungkinkan Anda untuk melonggarkan pentingnya urutan parameter:fn(name:"John Doe", age:36)

Tidak setiap bahasa mengizinkan hal-hal seperti itu. Jadi bagaimana?

c) Anda dapat menggunakan Kamus / Hashmap / Asosiatif Array sebagai parameter: mis. Javascript akan mengizinkan hal berikut: fn({"name":"John Doe", age:36})yang tidak jauh dari (b).

d) Tentu saja jika Anda bekerja dengan bahasa yang diketik secara statis seperti Java. Anda bisa menggunakan Hashmap , tetapi Anda akan kehilangan informasi jenis (misalnya ketika bekerja dengan HashMap<String, Object>) ketika parameter memiliki tipe yang berbeda (dan perlu dilemparkan).

Langkah logis berikutnya adalah untuk melewatkan Object(jika Anda menggunakan Java) dengan properti yang sesuai atau sesuatu yang lebih ringan seperti struct (jika Anda menulis misalnya C # atau C / C ++).

Aturan praktis:

1) Kasus terbaik - metode Anda tidak memerlukan parameter sama sekali

2) Kasus bagus - metode Anda membutuhkan satu parameter

3) Kasing yang dapat ditoleransi - metode Anda membutuhkan dua parameter

4) Semua kasus lain harus di refactored

Thomas Junk
sumber
0

Seringkali objek yang kompleks sebagai parameter lebih baik - versi parameter yang disebutkan oleh orang miskin yang bekerja pada sebagian besar platform. Dan membuka pintu ke parameter dengan perilaku untuk boot.

Sebagai contoh sebagian besar hal yang tidak boleh Anda lakukan, Anda mungkin ingin mencoba membaca dokumentasi perpustakaan standar PHP.

Wyatt Barnett
sumber
0

Saya biasanya memesannya dengan yang diperlukan terlebih dahulu, daripada dengan ukuran impor dan frekuensi penggunaan gabungan menurut "perasaan" (dapat dilihat sebagai ORDER BY required DESC, SOME_MAGIC_FEELING(importancy,frequency)) dan tidak sesuai dengan praktik tertentu.

Namun, seperti yang telah dicatat orang lain, saya pikir masalah mendasar yang membuat masalah ini adalah menggunakan terlalu banyak parameter (IMHO, apa pun> 3 terlalu banyak) dan itulah masalah sebenarnya yang harus Anda atasi. Ada posting yang menarik tentang itu di blog rebecca murphey.

Saya pikir ketika Anda hanya memiliki 1-3 argumen, urutan yang benar cukup jelas dan Anda hanya "merasakan" apa yang benar.

shesek
sumber
0

Mirip dengan jawaban @ Wyatt Barnetts, apa pun lebih dari beberapa parameter atau parameter yang sangat eksplisit untuk metode ini, saya akan merekomendasikan melewati objek sebagai gantinya. Ini biasanya lebih mudah untuk memperbarui / memelihara, lebih jelas untuk membaca, dan menghilangkan keharusan untuk khawatir tentang pemesanan . Juga, terlalu banyak parameter untuk suatu metode adalah bau kode dan ada pola refactoring umum yang dapat Anda ikuti untuk membantu memperbaikinya.

Contoh eksplisit:

public int add(int left, int right)
{
  return left + right;
}

Karena ini adalah contoh yang cukup jelas dan penambahan bersifat komutatif (pesanan tidak masalah) maka ikuti saja.

Namun, jika Anda menambahkan sesuatu yang lebih kompleks:

public SomeComplexReturnValue Calculate(int i, float f, string s, object o)
{
  // do work here
}

Akan menjadi:

public class SomeComplexInputForCalculation
{
  public int i; 
  public float f;
  public string s; 
  public object o;
}

public SomeComplexReturnValue Calculate(SomeComplexInputForCalculation input)
{
  // do work here
}

Semoga ini membantu...

longda
sumber
0

Pesanlah dengan cara apa pun yang menurut Anda paling cocok untuk mendapatkan kari. Misalnya, parameter fungsi terlebih dahulu.

alternatif
sumber
0

"Penting dulu" tidak berarti banyak. Ada beberapa konvensi.

Jika Anda melewati objek panggilan (sering disebut pengirim), itu berlaku lebih dulu.

Seharusnya ada beberapa kefasihan dalam daftar, yang berarti Anda harus tahu apa argumen tentang pada saat Anda membacanya. Contoh:

CopyFolder (jalur string, bool rekursif);

Jika Anda mengutamakan rekursif, itu akan membingungkan karena belum ada konteks. Jika Anda sudah sekarang tentang menyalin (1), folder (2), maka argumen rekursif mulai masuk akal.

Ini juga membuat fitur seperti IntelliSense bekerja dengan baik: pengguna belajar saat dia mengisi argumen, dia membangun pemahaman tentang metode dan apa yang dilakukannya. Demikian juga, kelebihan beban harus mempertahankan urutan yang sama untuk bagian yang sama.

Maka Anda mungkin masih menemukan ada argumen yang "sama" dalam hal ini dan Anda mungkin tergoda untuk membiarkan urutan bergantung pada jenis argumen. Hanya karena memiliki beberapa string berturut-turut dan kemudian beberapa booleans terlihat lebih baik. Pada tingkat tertentu ini akan menjadi seni daripada keterampilan.

Saya tidak terlalu peduli dengan pernyataan bahwa Anda harus membungkus semua argumen menjadi objek hanya untuk berakhir dengan satu argumen. Itu hanya membodohi diri sendiri (itu tidak membuat metode ini kurang kompleks, ia masih memiliki semua argumen ini, Anda hanya menyembunyikannya). Ini mungkin masih nyaman dilakukan jika Anda meneruskan set dari metode ke metode beberapa kali, refactoring pasti akan menjadi jauh lebih mudah, tetapi dari sisi desain hanya berpura-pura Anda membuat perbedaan. Ini tidak seperti Anda akan berakhir dengan objek bermakna yang mewakili sesuatu, itu hanya akan menjadi sekelompok argumen, tidak berbeda dari daftar dalam deklarasi metode. Itu tidak akan membuat paman Bob bahagia.

Martin Maat
sumber