Às vezes (raramente), parece que criar uma função que requer uma quantidade decente de parâmetros é a melhor rota. No entanto, quando o faço, sinto que estou frequentemente escolhendo a ordem dos parâmetros aleatoriamente. Eu costumo ir por "ordem de importância", com o parâmetro mais importante primeiro.
Existe uma maneira melhor de fazer isso? Existe uma maneira de "melhores práticas" de ordenar parâmetros que aprimore a clareza?
refactoring
clean-code
functions
parameters
order
Casey Patton
fonte
fonte
MessageBox.Show
. Olhe para isso também.Respostas:
Em geral: use-o .
Escreva um teste para sua função, um teste do mundo real.
Algo que você realmente gostaria de fazer com essa função .
E veja em que ordem você colocou essas anotações.
A menos que você já tenha (ou conheça) algumas funções que fazem algo semelhante.
Nesse caso: conforme o que eles já fazem, pelo menos para os primeiros argumentos.
Por exemplo , todos eles tomam um documento / objeto / ponteiro de arquivo / série de valores / coordenadas como o primeiro argumento (s)? Pelo amor de Deus, de acordo com esses argumentos .
Evite confundir seus colegas de trabalho e seu futuro eu .
fonte
Eu costumo seguir essas regras, embora nem sempre com a mesma precedência. Acho que agora é um processo de pensamento automático e não penso demais, exceto pelo design público da API .
Funil de seleção
1. Semântica Primeiro
Especialmente no POO, escolha parâmetros com base em seu significado semântico para a ação ou mensagem. A assinatura de um método bem nomeado com um parâmetro bem nomeado deve:
(Por esses motivos, às vezes o uso de tipos ou aliases personalizados em vez de primitivos pode aumentar a expressividade da sua assinatura.)
2. Então Importância
O parâmetro mais "significativo" vem primeiro (ou próximo ...)
3. Então Frequência
A frequência também é importante, especialmente em um idioma em que você não tem parâmetros nomeados, mas pode ter valores padrão em parâmetros posicionais. Isso implica que a ordem dos parâmetros não varia e que, obviamente, você não pode definir os parâmetros N + 1 se desejar forçar o valor padrão do parâmetro N (exceto se o seu idioma tiver o conceito de parâmetro de marcador de posição) )
A boa notícia para você é que, geralmente, a frequência está relacionada à importância, de modo que isso acompanha o ponto anterior. E, provavelmente, cabe a você criar sua API para que ela tenha a semântica apropriada.
4. Não vamos esquecer a E / S
se seu método / função recebe alguma entrada e produz uma saída, e a última não deve ser "retornada" (por meio de uma declaração de retorno) ou "lançada" (usando um sistema de exceção), você terá a opção de passar valores de volta ao chamador usando seus outros parâmetros (ou o parâmetro de entrada). Isso está relacionado à semântica e, na maioria dos casos, faz sentido que os primeiros parâmetros definam a saída e os últimos parâmetros recebam a saída.
Além disso, uma outra abordagem para ter menos parâmetros e maximizar a semântica seria usar uma abordagem funcional ou definir um padrão do Construtor , para que você possa empilhar claramente suas entradas, definir suas saídas e recuperá-las quando necessário.
(Observe que eu não mencionei variáveis globais, porque por que você usaria uma, certo?)
Algumas coisas a considerar
Usabilidade
A maioria dos itens acima será exibida naturalmente se você seguir o conselho da ZJR : Use It!
Considere a refatoração
Se você se preocupa com a ordenação de parâmetros, talvez essa preocupação encontre sua raiz no exposto acima e no fato de sua API ter sido mal projetada. Se você tiver muitos parâmetros, é provável que algo possa ser componente / modularizado e refatorado .
Considere o desempenho
Lembre-se de que as implementações de alguns idiomas terão impactos muito importantes no gerenciamento de memória de tempo de execução ao usar parâmetros. Daí a razão pela qual os livros de estilos de muitos idiomas recomendam manter a lista de parâmetros simples e curta . Com no máximo 4 parâmetros, por exemplo. Deixo como um exercício para você descobrir o porquê.
A resposta de Bevan e a menção às recomendações do Clean Code também são definitivamente relevantes!
fonte
Eu respeitosamente afirmo que se preocupar com a ordenação de parâmetros está se preocupando com a coisa errada.
No livro do tio Bob, " Código Limpo ", ele defende, persuasivamente, que os métodos nunca devem ter mais de dois argumentos - e a maioria deve ter apenas um, se houver. Nesse caso, a encomenda é óbvia ou sem importância.
Embora imperfeitamente, estou tentando seguir o conselho do tio Bob - e está melhorando meu código.
Nos raros casos em que um método parece exigir mais informações, a introdução de um objeto de parâmetro é uma boa idéia. Normalmente, acho que esse é o primeiro passo para a descoberta de um novo conceito (objeto) que é fundamental para o meu algoritmo.
fonte
Eu tento colocar os parâmetros IN primeiro, os parâmetros OUT em segundo. Existem também algumas ordens naturais, por exemplo,
createPoint(double x, double y)
é fortemente preferívelcreatePoint(double y, double x)
.fonte
addAllTo(target, something1, something2)
.Nunca vi uma "prática recomendada" documentada em relação a esse tópico específico, mas meu padrão pessoal é listá-las na ordem em que aparecerão no método para o qual estão sendo usadas ou se o método é mais passagem para uma camada de dados, listarei-os na ordem em que apareceriam no esquema db ou nos métodos da camada de dados.
Além disso, quando há várias sobrecargas de um método, percebo que a maneira típica é listá-las começando com parâmetros comuns a todos (ou à maioria) dos métodos, com cada método diferente sendo anexado ao final para cada sobrecarga de método, como :
fonte
Ordem: entrada (s), saída (s), parâmetros opcionais.
fonte
Costumo seguir a convenção C / C ++ de colocar os
const
parâmetros primeiro (ou seja, os parâmetros que você passa por valor) e depois os que você passa por referência. Esse pode não ser necessariamente o método correto para chamar funções, mas, se você estiver interessado em saber como cada compilador manipula parâmetros, consulte os seguintes links para as regras que regem e / ou a ordem em que os parâmetros são colocados na pilha.http://msdn.microsoft.com/en-us/library/zthk2dkh%28v=vs.80%29.aspx
http://en.wikipedia.org/wiki/Calling_convention
fonte
Normalmente, eu apenas uso a ordenação de parâmetros "o que parece menos cítrico". Quanto menos vezes eu precisar ir para a definição de método / função, melhor. E é bom ter parâmetros nomeados que são descritivos para o que eles são usados, dessa maneira, quando a pequena dica de ferramenta aparece (VS), isso torna ainda mais fácil.
Se você tiver linhas e linhas de parâmetros, poderá considerar um design diferente. Volte e veja como você pode dividir isso em mais funções / métodos. Apenas uma ideia, mas quando tenho uma dúzia de parâmetros em minha função, quase sempre não é um problema de parâmetro, mas um problema de design.
fonte
O uso de vários parâmetros geralmente é um indicador claro de que você viola o SRP neste método. É improvável que um método que precise de muitos parâmetros faça apenas uma coisa. A excitação pode ser uma função matemática ou um método de configuração, onde de fato vários parâmetros são necessários. Eu evitaria vários parâmetros, pois o diabo evita a água benta. Quanto mais parâmetros você usa em um método, maior a chance de o método ser (também) complexo; quanto mais complexidade significa: mais difícil de manter e isso é menos desejável.
No princípio você está escolhendo aleatoriamente . Claro que você pode pensar que o parâmetro A é mais relevante que o parâmetro B ; mas pode não ser o caso dos usuários da sua API, que consideram B o parâmetro mais relevante. Portanto, mesmo se você estivesse atento na escolha do pedido - para outros, isso poderia parecer aleatório .
Existem várias maneiras de sair:
a) O caso trivial: Não use mais de um parâmetro.
b) Como você não especificou qual idioma você escolheu, existe a chance de você escolher um idioma com parâmetros nomeados . Este é um bom açúcar sintático, que permite diminuir a importância da ordem dos parâmetros:
fn(name:"John Doe", age:36)
Nem todo idioma permite essas sutilezas. Então o que então?
c) Você pode usar um Dicionário / Hashmap / Matriz associativa como parâmetro: por exemplo, o Javascript permitiria o seguinte: o
fn({"name":"John Doe", age:36})
que não está longe de (b).d) Obviamente, se você trabalha com uma linguagem estaticamente tipada como Java. você poderia usar um Hashmap , mas perderia informações de tipo (por exemplo, ao trabalhar com
HashMap<String, Object>
) quando os parâmetros tivessem tipos diferentes (e precisassem ser convertidos).O próximo passo lógico seria passar um
Object
(se você estiver usando Java) com propriedades apropriadas ou algo mais leve como uma estrutura (se você escrever, por exemplo, C # ou C / C ++).Regra prática:
1) Melhor caso - seu método não precisa de nenhum parâmetro
2) Bom caso - seu método precisa de um parâmetro
3) Caso tolerável - seu método precisa de dois parâmetros
4) Todos os outros casos devem ser refatorados
fonte
Muitas vezes, um objeto complexo como parâmetro é melhor - uma versão pobre de parâmetros nomeados que funciona na maioria das plataformas. E abre a porta para parâmetros com comportamento para inicializar.
Para um exemplo da maioria das coisas que você não deve fazer, tente ler a documentação padrão da biblioteca do PHP.
fonte
Normalmente, eu os ordeno com o necessário primeiro, do que por alguma medida combinada de importância e frequência de uso de acordo com um "sentimento" (pode ser visto como
ORDER BY required DESC, SOME_MAGIC_FEELING(importancy,frequency)
) e não de acordo com qualquer prática específica.No entanto, como outros observaram, acho que o problema subjacente que torna esse problema está usando muitos parâmetros (IMHO, qualquer coisa> 3 é demais) e esse é o problema real que você deve abordar. Há um post interessante sobre isso no blog de Rebecca Murphey.
Eu acho que quando você tem apenas 1 a 3 argumentos, a ordem correta é bastante óbvia e você apenas "sente" o que é certo.
fonte
Semelhante à resposta do @Wyatt Barnetts, qualquer coisa além de alguns parâmetros ou parâmetros muito explícitos para o método, eu recomendaria a passagem de um objeto. Isso geralmente é mais fácil de atualizar / manter, mais claro para ler e remove a necessidade de se preocupar com pedidos . Além disso, muitos parâmetros para um método são um cheiro de código e existem padrões de refatoração comuns que você pode seguir para ajudar a corrigi-lo.
Exemplo explícito:
Como esse é um exemplo bem definido e a adição é comutativa (a ordem não importa), basta seguir com ele.
No entanto, se você adicionar algo mais complexo:
Se tornaria:
Espero que isto ajude...
fonte
Encomende da maneira que achar que o curry provavelmente se beneficiará. Por exemplo, parâmetros de função primeiro.
fonte
"Importante primeiro" não significa muito. Existem algumas convenções.
Se você passar o objeto de chamada (geralmente chamado remetente), isso ocorrerá primeiro.
Deve haver alguma fluência na lista, o que significa que você deve saber sobre o que é um argumento no momento em que o lê. Exemplo:
CopyFolder (caminho da string, bool recursivo);
Se você colocasse recursiva primeiro, seria confuso porque ainda não há contexto. Se você já se trata de copiar (1), uma pasta (2), o argumento recursivo começa a fazer sentido.
Isso também faz com que os recursos semelhantes ao IntelliSense funcionem bem: o usuário aprende à medida que preenche os argumentos, cria uma compreensão do método e do que ele faz. Da mesma forma, as sobrecargas devem manter a mesma ordem para as peças iguais.
Então você ainda pode achar que existem argumentos "iguais" a esse respeito e pode ficar tentado a deixar a ordem depender do tipo do argumento. Só porque ter duas cordas seguidas e depois dois booleanos parece melhor. Em algum nível, isso se tornará uma arte e não uma habilidade.
Não me importo muito com a afirmação de que você deve agrupar todos os argumentos em um objeto apenas para terminar com um único argumento. Isso é apenas enganar a si mesmo (ele não torna o método menos complexo, ainda possui todos esses argumentos, você apenas os ocultou). Isso ainda pode ser conveniente se você passar o conjunto de método para método algumas vezes, a refatoração certamente se tornará muito mais fácil, mas em termos de design, é apenas fingir que você está fazendo a diferença. Não é como se você acabasse com um objeto significativo que represente algo; será apenas um monte de argumentos, não diferentes da lista na declaração do método. Não fará o tio Bob feliz.
fonte