Rotinas podem ter parâmetros, isso não é novidade. Você pode definir quantos parâmetros precisar, mas muitos deles dificultam a compreensão e a manutenção de sua rotina.
Obviamente, você pode usar uma variável estruturada como solução alternativa: colocar todas essas variáveis em uma única estrutura e passá-la para a rotina. De fato, o uso de estruturas para simplificar as listas de parâmetros é uma das técnicas descritas por Steve McConnell no Code Complete . Mas como ele diz:
Programadores cuidadosos evitam agrupar dados mais do que é logicamente necessário.
Portanto, se sua rotina possui muitos parâmetros ou você usa uma estrutura para disfarçar uma grande lista de parâmetros, provavelmente está fazendo algo errado. Ou seja, você não está mantendo o acoplamento solto.
Minha pergunta é: quando posso considerar uma lista de parâmetros muito grande? Eu acho que mais de 5 parâmetros, são muitos. O que você acha?
fonte
Respostas:
Quando é que algo considerado tão obsceno que pode ser regulamentado, apesar da garantia da 1ª Emenda à liberdade de expressão? Segundo o juiz Potter Stewart, "eu sei quando vejo". O mesmo vale aqui.
Eu odeio fazer regras rígidas e rápidas como essa, porque a resposta muda não apenas dependendo do tamanho e do escopo do seu projeto, mas acho que muda até o nível do módulo. Dependendo do que o seu método está fazendo ou do que a classe deve representar, é bem possível que 2 argumentos sejam muitos e sejam um sintoma de muito acoplamento.
Eu sugeriria que, fazendo a pergunta em primeiro lugar e qualificando sua pergunta tanto quanto você, você realmente sabe tudo isso. A melhor solução aqui não é confiar em um número rígido e rápido, mas procurar análises de projeto e de código entre seus pares para identificar áreas em que você tem baixa coesão e acoplamento rígido.
Nunca tenha medo de mostrar a seus colegas o seu trabalho. Se você tem medo, esse é provavelmente o sinal maior de que algo está errado com o seu código e que você já o conhece .
fonte
Uma função só pode ter muitos parâmetros se alguns deles forem redundantes. Se todos os parâmetros forem utilizados, a função deverá ter o número correto de parâmetros. Tome esta função frequentemente usada:
São 12 parâmetros (9 se você agrupar x, y, weh como um retângulo) e também existem parâmetros derivados do nome da classe. Como você reduziria isso? Deseja reduzir o número mais ao ponto?
Não deixe que o número de parâmetros o incomode, apenas verifique se é lógico e bem documentado e deixe que o intellisense * o ajude.
* Outros assistentes de codificação estão disponíveis!
fonte
No Código Limpo , Robert C. Martin dedicou quatro páginas ao assunto. Aqui está a essência:
fonte
<algorithm>
, agisse em um objeto de alcance. Coleções seriam intervalos, mas nem todos os intervalos seriam coleções. E, de fato, o impulso já fez isso. De qualquer forma, o que quero dizer é que uma biblioteca amplamente usada ignora esse conselho; portanto, o pior que lhe é garantido, se você também fizer isso, é que muitos de seus milhões de usuários mexerão com pequenas simplificações em sua interface ;-)Alguns códigos com os quais trabalhei no passado usavam variáveis globais apenas para evitar a passagem de muitos parâmetros.
Por favor, não faça isso!
(Usualmente.)
fonte
Se você começar a contar mentalmente os parâmetros na assinatura e combiná-los com a chamada, é hora de refatorar!
fonte
Muito obrigado por todas as suas respostas:
Foi um pouco surpreendente encontrar pessoas que também pensam (como eu) que 5 parâmetros são um bom limite para a sanidade do código.
Geralmente, as pessoas tendem a concordar que um limite entre 3 e 4 é uma boa regra geral. Isso é razoável, pois as pessoas costumam ter problemas contando mais de 4 coisas.
Como aponta Milão , em média as pessoas podem manter mais ou menos 7 coisas na cabeça por vez. Mas acho que você não pode esquecer que, ao projetar / manter / estudar uma rotina, você deve ter em mente mais coisas do que apenas parâmetros.
Algumas pessoas consideram que uma rotina deve ter tantos argumentos quanto necessário. Concordo, mas apenas em alguns casos específicos (chamadas para APIs do SO, rotinas em que a otimização é importante etc.). Sugiro ocultar a complexidade dessas rotinas adicionando uma camada de abstração logo acima dessas chamadas sempre que possível.
usuario tem algumas idéias interessantes sobre isso. Se você não quiser ler os comentários dele, resumo para você: em poucas palavras, depende :
A moral aqui é não ter medo de mostrar seu código aos colegas, discutir com eles e tentar "identificar áreas onde você tem baixa coesão e acoplamento rígido" .
Finalmente, acho que wnoise concorda muito com Nick e conclui sua contribuição satírica com essa visão poética (veja os comentários abaixo) da arte da programação:
fonte
Esta resposta assume um idioma OO. Se você não estiver usando um - pule esta resposta (em outras palavras, não é uma resposta independente do idioma).
Se você estiver passando mais de três parâmetros (principalmente tipos / objetos intrínsecos), não é "muitos", mas pode haver uma chance de criar um novo objeto.
Procure grupos de parâmetros passados para mais de um método - mesmo um grupo passado para dois métodos quase garante que você deva ter um novo objeto lá.
Então você refatora a funcionalidade em seu novo objeto e não acredita no quanto isso ajuda seu código e seu entendimento da programação OO.
fonte
Parece que existem outras considerações além do mero número, aqui estão algumas que vêm à mente:
relação lógica com o objetivo principal da função x configurações pontuais
Se forem apenas sinalizadores de ambiente, o agrupamento pode ser muito útil
fonte
Um dos epigramas de programação conhecidos de Alan Perlis (recontado no ACM SIGPLAN Notices 17 (9), setembro de 1982) afirma que "Se você tem um procedimento com 10 parâmetros, provavelmente perdeu alguns".
fonte
De acordo com Steve McConnell no Code Complete , você deve
fonte
Para mim, quando a lista cruza uma linha no meu IDE, é um parâmetro a mais. Eu quero ver todos os parâmetros em uma linha sem quebrar o contato visual. Mas essa é apenas a minha preferência pessoal.
fonte
Eu geralmente concordo com 5, no entanto, se houver uma situação em que eu preciso de mais e for a maneira mais clara de resolver o problema, eu usaria mais.
fonte
Sete coisas na memória de curto prazo?
fonte
Nos Piores 5 Snippets de Código , verifique o segundo, "Isso é um construtor". Possui mais de 37 ⋅ 4 ≈ 150 parâmetros:
fonte
Um mais que o necessário. Não pretendo ser simplista, mas há algumas funções que necessariamente precisam de algumas opções. Por exemplo:
Existem 6 argumentos, e cada um deles é essencial. Além disso, não há um vínculo comum entre eles para justificá-los. Talvez você possa definir "struct mmapargs", mas isso seria pior.
fonte
prot
eflags
poderia ter sido reunido se o designer sentisse que 5 era, de alguma forma, um número mágico muito melhor que 6. Um pouco como a maneira queopen
combina o modo de leitura / gravação com todos os outros sinalizadores diversos. E talvez você possa se livraroffset
especificando que a seção mapeada começa na posição atual de busca defiledes
. Não sei se existem situações em que você podemmap
uma região que não é capaz delseek
acessar, mas, se não, não é estritamente necessário.mmap
é uma boa ilustração do fato de que alguns designers e usuários preferem uma grande lista longa de parâmetros, enquanto outros preferem seguir algumas etapas preparando um número menor de parâmetros antes de fazer a chamada.De acordo com as práticas recomendadas do Perl , 3 é aceitável, 4 é demais. É apenas uma orientação, mas em nossa loja é isso que tentamos seguir.
fonte
Eu mesmo desenharia o limite para funções públicas em 5 parâmetros.
IMHO, listas longas de parâmetros são aceitáveis apenas em funções auxiliares particulares / locais que devem ser chamadas apenas de alguns locais específicos no código. Nesses casos, talvez você precise repassar muitas informações de estado, mas a legibilidade não é uma grande preocupação, pois apenas você (ou alguém que manterá seu código e deve entender os fundamentos do seu módulo) precisa se preocupar com chamando essa função.
fonte
Uma questão relacionada que você deve considerar é quão coesa é a rotina. Um grande número de parâmetros pode ser um cheiro que está lhe dizendo que a própria rotina está tentando fazer muito e, portanto, é suspeita de coesão. Concordo que um número rígido e rápido de parâmetros provavelmente é impossível, mas acho que uma rotina de alta coesão implicaria um número baixo de parâmetros.
fonte
97 soa exatamente certo.
Menos e você perde flexibilidade.
fonte
Eu paro em três parâmetros como regra geral. Mais e é hora de passar uma matriz de parâmetros ou um objeto de configuração, o que também permite que parâmetros futuros sejam adicionados sem alterar a API.
fonte
Uma restrição de comprimento em uma lista de parâmetros é apenas mais uma restrição. E restrição significa violência aplicada. Parece engraçado, mas você pode não ser violento mesmo durante a programação. Apenas deixe o código ditar as regras. É óbvio que, se você tiver muitos parâmetros, o corpo do método function / class será grande o suficiente para utilizá-los. E trechos de código grandes geralmente podem ser refatorados e divididos em partes menores. Assim, você obtém uma solução contra ter muitos parâmetros como bônus grátis, pois eles são divididos entre os menores pedaços de código refatorados.
fonte
Uma coisa que eu apontaria da perspectiva do desempenho é que, dependendo de como você passa parâmetros para um método, a passagem de muitos parâmetros por valor atrasará o programa, pois cada parâmetro deve ser copiado e, em seguida, colocado na pilha.
Usar uma única classe para abranger todos os parâmetros funcionaria melhor porque um único parâmetro passado por referência seria elegante, limpo e rápido!
fonte
Segundo mim, pode haver casos em que você excederá 4 ou algum número fixo. Coisas a serem observadas
Do ponto de vista da facilidade de uso ou da facilidade de leitura do código, acho que quando você precisa digitar sua assinatura de método, isso deve fazer com que você pare e pense: a menos que se sinta impotente e todos os esforços para reduzir a assinatura levam a nenhum resultado. Algumas bibliotecas muito boas no passado e no presente usam mais de 4-5 carrinhos de bebê.
fonte
Minha regra geral é que preciso lembrar os parâmetros por tempo suficiente para olhar para uma chamada e dizer o que ela faz. Então, se eu não consigo olhar para o método e, em seguida, mudar para a chamada de um método e lembrar qual parâmetro faz o que, então há muitos.
Para mim, isso equivale a cerca de 5, mas eu não sou tão brilhante. Sua milhagem pode variar.
Você pode criar um objeto com propriedades para reter os parâmetros e passá-lo se exceder o limite que você definir. Consulte o livro Refatoração de Martin Fowler e o capítulo sobre como simplificar as chamadas de método.
fonte
Depende bastante do ambiente em que você está trabalhando. Tomemos, por exemplo, javascript. Em javascript, a melhor maneira de passar parâmetros é usar objetos com pares de chave / valor, o que, na prática, significa que você tem apenas um parâmetro. Em outros sistemas, o ponto ideal será às três ou quatro.
No final, tudo se resume ao gosto pessoal.
fonte
Concordo que 3 é bom, 4 é demais como orientação. Com mais de três parâmetros, você está inevitavelmente executando mais de uma tarefa. Mais de uma tarefa deve ser dividida em métodos separados.
No entanto, se eu olhasse para o projeto mais recente em que trabalhei, as exceções seriam muitas e a maioria dos casos seria difícil de reduzir para três parâmetros.
fonte
Se eu tiver 7 a 10 parâmetros em uma rotina, analiso agrupá-los em uma nova classe, mas não se essa classe não passasse de um monte de campos com getters e setters - a nova classe precisa fazer algo diferente de valores aleatórios e Fora. Caso contrário, eu prefiro aturar a longa lista de parâmetros.
fonte
É um fato conhecido que, em média, as pessoas podem manter 7 +/- 2 coisas na cabeça por vez. Eu gosto de usar esse princípio com parâmetros. Supondo que todos os programadores sejam pessoas inteligentes acima da média, eu diria que tudo que é 10+ é demais.
BTW, se os parâmetros forem semelhantes de alguma forma, eu os colocaria em um vetor ou lista em vez de uma estrutura ou classe.
fonte
Basearia minha resposta na frequência com que a função é chamada.
Se é uma função init que é chamada apenas uma vez, deixe 10 parms ou mais, quem se importa.
Se for chamado várias vezes por quadro, então eu tendem a fazer uma estrutura e apenas passar um ponteiro para ela, pois isso tende a ser mais rápido (supondo que você não esteja reconstruindo a estrutura todas as vezes).
fonte
De acordo com Jeff Bezos, da Amazon, não pode mais do que ser alimentado com duas pizzas :
fonte