Qual è la migliore pratica sull'ordinare i parametri in una funzione?

45

A volte (raramente), sembra che la creazione di una funzione che richiede una quantità decente di parametri sia la via migliore. Tuttavia, quando lo faccio, mi sento come se stessi spesso scegliendo l'ordine dei parametri a caso. Di solito vado per "ordine di importanza", con il parametro più importante prima.

C'è un modo migliore per farlo? Esiste un metodo di "best practice" per ordinare parametri che aumentino la chiarezza?

    
posta Casey Patton 16.08.2011 - 03:32
fonte

13 risposte

47

In generale: usalo .

Scrivi un test per la tua funzione, un test del mondo reale.
Qualcosa ti piacerebbe davvero fare con quella funzione .

E vedi in che ordine li hai messi giù.

A meno che tu non abbia già (o ne sappia) alcune funzioni che fanno qualcosa di simile.
In tal caso: conforme a quello che fanno già, almeno per i primi argomenti.

per esempio prendono tutti un documento / oggetto / puntatore di file / serie-di-valori / coordinate come primo argomento / i? Per l'amor di dio conformi a quegli argomenti .

Evita confondere i tuoi colleghi e il tuo sé futuro .

    
risposta data 16.08.2011 - 03:43
fonte
26

Di solito vado con queste regole, anche se non sempre con la stessa precedenza. Immagino sia un processo di pensiero automatico ora, e io non lo penso troppo, tranne che per la progettazione dell'API pubblica .

Selezione canalizzazione

  1. Semantica
  2. Importanza / Rilevanza
  3. Frequenza di utilizzo
  4. Preoccupazioni I / O

1. Prima semantica

Specialmente in OOP, seleziona i parametri in base alla loro importanza semantica per l'azione o il messaggio. La firma di un metodo ben denominato con un parametro ben denominato dovrebbe:

  • è naturale chiamare,
  • essere auto-descrittivi in termini di intento e comportamento.

(Per questi motivi, a volte l'uso di tipi o alias personalizzati anziché primitivi potrebbe aumentare l'espressività della firma.)

2. Quindi importanza

Il parametro più "significativo" viene prima (o successivo ...)

3. Quindi frequenza

Anche la frequenza conta, specialmente in una lingua in cui non si hanno parametri con nome ma possono avere valori predefiniti su parametri posizionali. Ciò implica che l'ordine dei parametri non varia e che ovviamente non puoi impostare i parametri N + 1 se vuoi forzare il valore predefinito del parametro Nth (eccetto se la tua lingua ha un concetto di parametro di segnaposto ).

La buona notizia per te è che di solito la frequenza si riferisce all'importanza, quindi va di pari passo con il punto precedente. E poi probabilmente spetta a te creare la tua API affinché abbia la semantica appropriata.

4. Non dimentichiamo I / O

se il tuo metodo / funzione prende un input e produce un output, e quest'ultimo non deve essere "restituito" (tramite un'istruzione return) o "gettato" (usando un sistema di eccezione), allora ti rimane opzione per passare i valori al chiamante usando gli altri parametri (o il parametro di input). Ciò si riferisce alla semantica e nella maggior parte dei casi avrà senso che i primi parametri definiscano l'output e gli ultimi parametri ricevano l'output.

Inoltre, un altro approccio per avere meno parametri e massimizzare la semantica sarebbe utilizzare un approccio funzionale o definire un modello di generatore , così puoi impilare chiaramente i tuoi input, definire i tuoi output e recuperarli quando necessario.

(Si noti che non cito le variabili globali, perché dovresti usarne una, giusto?)

Alcune cose da considerare

  • Usabilità

    La maggior parte di quanto sopra mostrerà naturalmente se segui il consiglio di ZJR: Usalo!

  • Prendi in considerazione i refactoring

    Se ti preoccupi dell'ordinamento dei parametri, forse questa preoccupazione trova la sua radice in quanto sopra e nel fatto che la tua API è progettata male. Se hai troppi parametri, qualcosa può molto probabilmente essere componente / modularizzato e refactored .

  • Considera le prestazioni

    Tenere presente che l'implementazione di alcuni linguaggi inciderà in modo molto importante sulla gestione della memoria di runtime quando si utilizzano i parametri. Da qui il motivo per cui i libri di stile di molti linguaggi consigliano di mantenere l'elenco dei parametri semplice e breve . Ad un massimo di 4 parametri, ad esempio. Lascio come esercizio per te capire perché.

  • Bevan's risposta e menzione dei I consigli di Clean Code sono sicuramente altrettanto importanti!

risposta data 16.08.2011 - 04:12
fonte
19

Rispetto rispettosamente che preoccuparsi dell'ordinamento dei parametri è preoccupante per la cosa sbagliata.

Nel libro di Uncle Bob " Pulisci codice " egli sostiene, in modo persuasivo, che i metodi non dovrebbero mai avere più di due argomenti - e la maggior parte dovrebbe avere solo uno, se ce ne sono. In questo caso, l'ordine è ovvio o non importante.

Tuttavia, imperfettamente, sto cercando di seguire il consiglio dello Zio Bob - e sta migliorando il mio codice.

Nei rari casi in cui un metodo sembra richiedere più informazioni, introducendo un oggetto parametro è una buona idea. Di solito, trovo che questo sia il primo passo verso la scoperta di un nuovo concetto (oggetto) che è la chiave del mio algoritmo.

    
risposta data 16.08.2011 - 05:52
fonte
10

Provo a mettere prima i parametri IN, i secondi parametri OUT. Ci sono anche degli ordini naturali, ad es. createPoint(double x, double y) è strongmente preferibile a createPoint(double y, double x) .

    
risposta data 16.08.2011 - 04:01
fonte
6

Non ho mai visto una "best practice" documentata su questo particolare argomento, ma il mio standard personale è elencarle nell'ordine in cui appariranno nel metodo per cui sono utilizzate o se il metodo è più di un pass-through a un livello dati li elencherò nell'ordine in cui apparirebbero nei metodi dello schema db o del livello dati.

Inoltre, quando ci sono più sovraccarichi di un metodo, noto che il modo tipico è quello di elencarli iniziando con i parametri che sono comuni a tutti (o la maggior parte) dei metodi con ogni diverso metodo aggiunto alla fine per ogni metodo di sovraccarico come:

void func1(string param) { }
void func2(string param, int param2) { }
void func3(string param, string param3) { }
void func3(string param, int param2, string param3) { }
    
risposta data 16.08.2011 - 03:42
fonte
6

Ordine: input (s), output (s), parametri opzionali.

    
risposta data 16.08.2011 - 05:19
fonte
3

Spesso seguo la convenzione C / C ++ di inserire prima i parametri const (cioè i parametri che si passano per valore) e poi quelli che si passano per riferimento. Questo potrebbe non essere necessariamente il metodo corretto per chiamare le funzioni ma, se sei interessato al modo in cui ogni compilatore gestisce i parametri, dai uno sguardo ai seguenti link per le regole che governano e / o l'ordine in cui i parametri vengono inseriti nello stack.

link

link

    
risposta data 16.08.2011 - 04:11
fonte
1

Di solito vado con l'ordinamento dei parametri "ciò che sembra meno cyprico". Il minor numero di volte che ho bisogno di andare alla definizione metodo / funzione, meglio è. Ed è bello avere parametri denominati che descrivono come sono utilizzati, in questo modo quando viene visualizzato il piccolo suggerimento (VS), allora è ancora più semplice.

Se hai linee e linee di parametri potresti prendere in considerazione un design diverso. Tornare indietro e vedere come è possibile suddividerlo in più funzioni / metodi. Solo un'idea, ma quando ho una dozzina di parametri nella mia funzione non è quasi sempre un problema con i parametri, ma un problema di progettazione.

    
risposta data 16.08.2011 - 05:01
fonte
1

Ordinalo in qualunque modo tu pensi che molto probabilmente trarranno beneficio. Ad esempio, prima i parametri di funzione.

    
risposta data 08.03.2012 - 23:14
fonte
1

Sometimes (rarely), it seems that creating a function that takes a decent amount of parameters is the best route.

L'uso di diversi parametri è spesso un chiaro indicatore, che violi il SRP in questo metodo. È improbabile che un metodo, che richiede molti parametri, faccia solo una cosa. L'escpetion può essere una funzione matematica o un metodo di configurazione, dove infatti diversi parametri sono necessari. Eviterei più parametri poiché il diavolo evita l'acqua santa. Più parametri usi in un metodo, maggiore è la possibilità che il metodo sia (troppo) complesso; più complessità significa: più difficile da mantenere e meno desiderabile.

However, when I do, I feel like I'm often choosing the ordering of the parameters at random. I usually go by "order of importance", with the most important parameter first.

In principio si sceglie a caso . Ovviamente si potrebbe pensare che il parametro A sia più rilevante del parametro B ; ma questo potrebbe non essere il caso per gli utenti della tua API, che pensano che B sia il parametro più rilevante. Quindi, anche se tu fossi attento nella scelta dell'ordine, per gli altri potrebbe sembrare random .

Is there a better way to do this? Is there a "best practice" way of ordering parameters that enhances clarity?

Ci sono diversi modi per uscire:

a) Il caso banale: non utilizzare più di un parametro.

b) Come non hai specificato, quale lingua hai scelto, c'è la possibilità che tu abbia scelto una lingua con named parameters . Questo è zucchero sintattico che ti consente di ridurre il significato dell'ordine dei parametri: fn(name:"John Doe", age:36)

Non tutte le lingue consentono tali sottigliezze. Allora, allora?

c) Potresti usare un dizionario / Hashmap / Array associativo come parametro: per esempio. Javascript consentirebbe quanto segue: fn({"name":"John Doe", age:36}) che non è molto lontano da (b).

d) Naturalmente se lavori con un linguaggio tipizzato staticamente come Java. potresti usare un Hashmap , ma potresti perdere informazioni sul tipo (ad esempio quando lavori con HashMap<String, Object> ) quando i parametri hanno tipi diversi (e devono essere lanciati).

Il prossimo passo logico sarebbe passare un Object (se si sta usando Java) con proprietà appropriate o qualcosa di più leggero come una struct (se si scrive ad esempio C # o C / C ++) .

Regola generale:

1) Best case: il tuo metodo ha bisogno del parametro no

2) Buon caso: il tuo metodo ha bisogno di un parametro

3) Caso tollerabile: il tuo metodo richiede due parametri

4) Tutti gli altri casi devono essere refactored

    
risposta data 09.02.2015 - 21:28
fonte
0

Spesso un oggetto complesso come parametro è migliore - una versione povera di parametri nominati che funziona sulla maggior parte delle piattaforme. E apre le porte ai parametri con il comportamento da avviare.

Per un esempio di ciò che non dovresti fare, potresti provare a leggere la documentazione della libreria standard di PHP.

    
risposta data 16.08.2011 - 06:17
fonte
0

Di solito li ordino con il requisito necessario, piuttosto che con qualche misura combinata di importanza e frequenza d'uso secondo un "sentimento" (può essere visto come ORDER BY required DESC, SOME_MAGIC_FEELING(importancy,frequency) ) e non secondo alcuna pratica specifica.

Tuttavia, come altri hanno notato, penso che il problema che sta alla base di questo problema sia l'utilizzo di troppi parametri (IMHO, qualsiasi cosa > 3 è troppa) e questo è il vero problema che dovresti affrontare. C'è un post interessante al riguardo sul blog di rebecca murphey.

Penso che quando hai solo 1-3 argomenti, l'ordine corretto è abbastanza ovvio e tu "senti" ciò che è giusto.

    
risposta data 16.08.2011 - 14:24
fonte
0

Simile alla risposta di @Wyatt Barnetts, niente più di alcuni parametri o parametri molto espliciti per il metodo, mi piacerebbe invece passare un oggetto. Normalmente questo è più facile da aggiornare / mantenere, più chiaro da leggere e elimina la necessità di preoccuparsi di ordinare . Inoltre, troppi parametri per un metodo sono un odore di codice e sono comuni pattern di refactoring che puoi seguire per aiutarti a correggerlo.

Esempio esplicito:

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

Poiché si tratta di un esempio abbastanza chiaramente definito e l'aggiunta è commutativa (l'ordine non ha importanza), quindi seguitela.

Tuttavia, se aggiungi qualcosa di più complesso:

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

Diventerebbe:

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

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

Spero che questo aiuti ...

    
risposta data 19.08.2011 - 03:16
fonte

Leggi altre domande sui tag