Stack Overflow em Português Asked on January 2, 2022
Prezo sempre por escrever meus códigos de maneira curta e legível. Meu lema é sempre pensar que “algum dia, alguém vai mexer no meu código e quero que a pessoa que o fizer entenda com facilidade”. Foi pensando assim, me veio a cabeça a questão dos parâmetros das funções.
Qual é o máximo de parâmetros eu deveria utilizar?
Digo isso porque eu, particularmente, tenho uma imensa dificuldade em usar funções que contenham mais de 4 parâmetros – e, como uma regra pessoal, se uma função que estou construindo acaba tendo mais parâmetros que isso, eu refaço ela toda, para não ter essa quantidade de parâmetros.
O meu sonho era conhecer quem foi a pessoa [iluminada] que teve a brilhante ideia de criar a função imagecopyresampled()
e bater um papo com ele!
Essa função tem 10 parâmetros!
bool imagecopyresampled ( resource $dst_image , resource $src_image , int $dst_x , int $dst_y , int $src_x , int $src_y , int $dst_w , int $dst_h , int $src_w , int $src_h )
Isso para mim [e creio que para muitos outros programadores] não ajuda nem um pouco. Seria muito fácil confundir um parâmetro, ou simplesmente nem saber o que cada coisa faz, por ser fácil se perder.
Eu sei que o site não permite perguntas baseadas em opiniões, mas não é meu objetivo aqui querer saber a opinião sobre a quantidade de parâmetros que devem ser usadas, mas sim se existe algum Design Pattern ou algum Guia de Estilo de codificação (como os PSR do PHP) que deem algum bom argumento sobre como a questão de número de parâmetros devem ser tratadas.
Existe algum padrão ou recomendação a respeito da quantidade ideal de parâmetros que pode ser utilizado numa função?
Criar uma função com muitos parâmetros seria um Anti-Pattern?
A recomendação mais conhecida de limite de parâmetros é do livro Clean Code na qual o Daniel citou em sua resposta.
Porém, esta percepção é diferente entre alguns autores e até mesmo entre as ferramentas de análise de código.
Por exemplo, considerada uma das referências no desenvolvimento de software, o livro Code Complete 2 do Steve McConnell diz que o limite de parâmetros é 7:
Limit the number of a routine's parameters to about seven
A ferramenta de análise de código SonarQube acusa um problema no código nas classes com mais de 7 parâmetros no construtor.
Porém, seja 3, 7 ou 10, eu entendo que eles são apenas um indicativo de que tem algo errado no seu método ou classe, mas não necessariamente que o problema existe.
Acredito que o pior indicativo de ter muitos parâmetros é que o código executado dentro do método varie conforme um parâmetro é passado ou não. Isto traz uma complexidade extra e preocupante para o método e, quando temos muitos parâmetros, as chances são grandes de o método ter este tipo de comportamento.
Mas nem sempre é assim se todos os parâmetros são usados. Imagine um método como este:
public Pessoa criar(nome, sobrenome, idade, cpf, genero, profissao,
rua, cidade, estado, pais, cep);
Temos 11 parâmetros, mas não existe muita dúvida do que ele faz e o método não tem nada de complexo, pois ele simplesmente cria um objeto pessoa com base nos parâmetros passados. Claro que é possível melhorar ele:
public Pessoa criar(new Nome(nome, sobrenome), idade, cpf, genero, profissao,
new Endereco(rua, cidade, estado, pais, cep));
Diminuindo para 6 parâmetros, e dos dois modos o método está condizente com seu propósito e a complexidade não mudou, apenas ficou um pouco mais organizado.
No caso de classes com muitos parâmetros, este problema pode ser particularmente grave se estamos falando de classes que levam o conceito de Service (camada de serviço).
No exemplo anterior eu criei uma classe Endereco
que recebeu 4 parâmetros, sendo todos eles usados e sem complexidade adicional no tratamento delas. Uso simples e direto dos parâmetros. Mas as classes de serviço não recebem no seu construtor apenas dados, mas sim outros serviços (por meio de injeção de dependência) que tem outras responsabilidades. Classes de Service assim, com muitas dependências de outras classes do mesmo tipo, provavelmente são classes que estão fazendo mais do que deveriam.
Na minha experiência, classes de serviço com mais de 5 parâmetros são forte candidatas a uma boa refatoração, pois normalmente elas acabam tendo vários métodos e nem todos estes métodos usam todos os services disponíveis e injetados via contrutor da classe. De certa forma, temos o mesmo problema dos métodos com muitas funções: alguns parâmetros do construtor acabam sendo opcionais dentro da classe dependendo do método chamado dentro dela.
Answered by Dherik on January 2, 2022
Não existe, e vou afirmar que qualquer um que diga que tem, perde credibilidade com engenheiros "de verdade".
Foi citado nas respostas um livro que eu acho que as pessoas devem ler. Mas ao mesmo tempo tenho medo que elas leiam. Se a pessoa estiver preparada para ler, ou seja, ter um pensamento crítico, entender método científico, já ter os fundamentos da engenharia de software, que sejam pragmáticos e neutros, sem falar em ser capaz de interpretar texto adequadamente e entender o contexto do livro, que não está escrito nele, aí lê-lo pode te dar ideias, provocar questionamentos, sugerir técnicas, e pode propor boas coisas.
Isso vale para tudo na vida.
Especialmente acho o livro desastroso na mão de quem não é capaz de selecionar o que ajuda e o que atrapalha para si. E é um problema no que não é óbvio. E obviedade depende de cada um.
Há quem considere que 17 linhas de código é o tamanho máximo que uma função deve ter. E não discuta com a pessoa. Eu sequer consigo imaginar porque não é 16, ou 18, ou 13, ou 23 (por alguma razão gostam de números primos).
Quando alguém afirma coisas que não podem ser afirmadas sem dizer que é uma brincadeira, ou que justifique profundamente, o que quase sempre é dizer para considerar como piada, desconfie do autor. Entregar algo "concreto" funciona bem como marketing. As pessoas gostam de respostas claras e diretas, mesmo que sejam falsas. Não fosse isso fake news não prosperava (e as pessoas não costumam sequer saber o que é fake news, a maioria acha que é a tradução literal). Validar o que a pessoa acredita, e isso é mais fácil quando ela tem pouca base sobre o que pensa, é muito poderoso. Tanto que até quem tem boa base filosófica cai nessa.
Um dos erros que comete-se é não olhar o contexto. O livro não tem um contexto claro, mas tem um implícito, e o fato de você não saber facilmente já é um indício que deve desconfiar do que tem ali. Depende do tipo de código, do tipo de equipe e do tipo de tecnologia usada.
Tem cenário que cabe algum critério. Mas não cabe em vários outros. O que vale é o bom senso. Acho que a citação do livro é interessante até isoladamente. Mas apenas se entender que isso é uma teoria útil, não uma prática sempre aplicável. Tem que olhar a alternativa. Será que ela é um benefício ou não?
Criar um objeto só para encapsular parâmetros que são naturalmente parâmetros, e não partes de um objeto, é uma das ideias mais estúpidas que eu já vi. Inclusive fere o conceito de coesão. Encapsular dados em um objeto único que faça todo sentido estarem juntos, e que isso pode ser usado em alguns lugares, faz muito sentido, em muitos casos.
Nada errado com ela, só acho que foi dado uma ênfase ao tipo de projeto e equipe sem considerar que mesmo dentro de uma equipe ou projeto tem necessidades diferentes em cada momento, em cada ponto. O contexto micro deve ser considerado mais que qualquer outra coisa. Achar que uma equipe decidir como fazer é bom, é interessante do ponto de vista político, mas não de engenharia (em alguns casos até faz também), cada um atirando para uma lado não é boa engenharia. Só me incomodou um pouco a último parágrafo que trata o aceitável de forma genérica. O que é compreensível que seja feito.
A resposta não é ruim. Só não concordo com a ideia básica dela, longe de ser errada. Não sou fascistoide.
Em geral não faz sentido em linguagens de baixa cerimônia, com códigos naturalmente autocontidos. Especialmente não faz sentido em PHP (ou não fazia na origem da linguagem, agora ela quer ser Java). E mesmo que fizesse não vejo porque não usar um array simples, até mesmo associativo que só exista naquele contexto. Criar uma classe só para isso já tende ser ruim em Java, em PHP mais ainda.
Porém Java tem uma justificativa. É uma linguagem que preza pela performance, e mandar vários parâmetros pode custar caro. E a única forma de criar uma estrutura heterogênea para passar por referências é criando uma classe. Ainda assim só haverá ganhos se não for criar o objeto só para isso, só se ele já existir em um contexto maior dentro da aplicação. Jamais será uma boa ideia criar a classe só para passar como parâmetro. Nem do ponto de vista de organização. Isso é complicação e não simplificação. As pessoas perderam a noção do que é simples.
Em PHP sem a performance ser um requisito e tendo outro mecanismo melhor faz menos sentido ainda.
É um direito de cada um ser autor do que deseja transmitir, mas adaptar Clean Code para PHP (original) seria interessante se a adaptação mandasse fazer quase tudo ao contrário (estou exagerando um pouco aqui :) ).
Curiosamente isso feito sem critério diminui a coesão e pode aumentar o acoplamento, e este é um conceito antigo, muito mais que o livro, esse sim ideia original e que faz sentido.
Um ponto interessante para mostrar que a citação em isolado já é falha, é que isso vale para funções ou para métodos. Com essa precisão toda da quantidade ideal colocada nas afirmações, ter um parâmetro de diferença já muda muito. Método tem um parâmetro a mais que não é visível, ele conta ou não?
Acho a resposta que era mais votada bastante sensível em relação a isso, só faltou justificar um pouco mais, por isso resolvi responder. Se tem vários autores dizendo coisas diferentes é a mostra cabal que não tem número ideal.
Claro, um número pequeno é interessante, ninguém pode negar.
Há quem diga que zero nem é bom, mas isso é fundamentalismo, há casos que a comunicação exige isso mesmo, pode ser que ele acesse recursos externos sem precisar de qualquer configuração, o que faria até um parâmetro ser exagero porque se for só para configurar a função, pode ser o caso de separar a função em mais que uma, mantendo como uma abstração para algo maior dentro do DRY.
Quando tem muitos parâmetros é cheiro ruim (code smell). Mas o que é ruim depende do contexto, até cheiro de gás (que é artificialmente ruim) é bom porque faz o que ele se propõe. Cheiro é indicador, não prova.
Talvez a resposta do gato mostre algo que mereça um objeto (não necessariamente classe), não por causa dos parâmetros, mas sim porque é coeso ser uma coisa só, para toda aplicação. Uma bem pensada já teria esse objeto naturalmente, aí não tem o que discutir. Minha crítica é criar a abstração sem motivo.
Eu sei por experiência própria que funções com mais de 4 ou 5 parâmetros costumam ter algo errado, mas nem todos. Sei que se tiver muitas funções assim, com os mesmos parâmetros costuma ser algo bem errado. Mas só costuma.
Um dos indicativos quando tem muitos parâmetros é que a função tem muitas responsabilidades, então a solução não é tentar diminuir o número de parâmetros é separar as responsabilidades, os parâmetros diminuirão naturalmente. Não adianta achar o problema, tem que achar a solução correta. Criar uma classe não é a única solução.
Forma curta (1) ou legível (2) nunca é escrever mais código (1) ou delegar para outro local (2). Escrevemos mais e em outro local quando precisa, quando traz uma vantagem maior que a desvantagem que isso traz junto.
Sempre alguém vai mexer no seu código, você, por exemplo. Poucas pessoas têm a habilidade de lembrar de tudo o que fez depois de um tempo. Também critico quem tem essa capacidade e a usa como se todos deveriam ter.
Viu? Tenho a mesma dificuldade que o AP, o número é próximo ao dele, e pouca coisa a mais que o livro. Mas já trabalhei bem com funções com 7 ou mais parâmetros. E onde tinha muitos a solução não era criar uma classe, porque não resolvia problema algum, só ficava um trecho mais curto, outros ficavam mais longos.
Um problema muito maior dessa função é que ela usa nomes pouco legíveis.
Tem linguagem que tem argumentos nomeados para evitar a dificuldade de entender o que está sendo passado. Se a linguagem não tem é uma pena, escolha ruim, mas ainda tem comentários, certo? Pode usar /*argumentoX*/
. Engraçado que ninguém pensa nessas coisas para resolver os problemas. Deve ser porque não está em nenhuma receita de bolo que tem por aí.
Não sei o contexto para falar mais sobre o exemplo mostrado na pergunta. Pode ser que mereça mesmo ter alguma forma para as coordenadas. Mas tenho dúvidas.
Não sei se PHP tem alguma recomendação oficial. Em geral essas recomendações são bobas e sendo de PHP torço um pouco mais o nariz já que coisas bem importantes de ter algo claro e objetivo, não tem.
Ter muitos parâmetros é claramente um antipattern. Só não ache que eles nunca devam ser usados ou que um número estabelecerá quando é normal ou não.
Nem falei do fato que parâmetro não é o mesmo que argumento. E que há casos que pode ter muitos parâmetros, mas usar mesmo poucos argumentos (em linguagens que possuem argumentos opcionais).
Answered by Maniero on January 2, 2022
Existem algumas recomendações na literatura. No livro Clean Code do Robert Martin, existe uma seção que menciona esse tópico especificamente (Capítulo 3, seção Function Arguments). Existe uma citação que é muito similar à sua percepção:
The ideal number of arguments for a function is zero (niladic). Next comes one (monadic), followed closely by two (dyadic). Three arguments (triadic) should be avoided where possible. More than three (polyadic) requires very special justification—and then shouldn’t be used anyway.
Porém, alguns outros autores e desenvoldores não concordam com essa abordagem e acreditam que seja muito idealista, pois em muitos cenários é realmente difícil chegar a uma função que receba uma quantidade de parâmetros menor. Para seguir à risca essa recomendação, muitas vezes é necessária a criação de estruturas de dados que funcionarão como wrappers para cada função/método.
Sabendo disso, o mais sensato a se fazer, seria definir qual é a quantidade aceitável de parâmetros que será utilizada dentro do seu time/projeto especificamente.
Answered by Daniel Vasconcelos on January 2, 2022
Há este princípio do livro Clean Code de Robert C. Martin, ele foi adaptado para PHP pela comunidade, não que as pessoas devem seguir à risca, mas tem que considerar o contexto e a justificativa.
No meu caso, adoto sempre para dar mais manutenibilidade e testabilidade, são dois fatores que estão no topo para adoção de algum desses princípios, logo em seguida vem a legibilidade.
Sendo assim, para a quantidade de parâmetros temos este exemplo:
Abordagem ruim
function createMenu(string $title, string $body, string $buttonText, bool $cancellable): void
{
// ...
}
Abordagem boa
class MenuConfig
{
public $title;
public $body;
public $buttonText;
public $cancellable = false;
}
$config = new MenuConfig();
$config->title = 'Foo';
$config->body = 'Bar';
$config->buttonText = 'Baz';
$config->cancellable = true;
function createMenu(MenuConfig $config): void
{
// ...
}
O principio diz que dois argumentos ou menos já esta bom, três já é questão de repensar sua função e deixa-la com menos paramentos.
No caso desta função que você ilustrou na pergunta, esta abordagem acima já seria suficiente para deixa-la mais simples, ou dividir em funções menores.
Answered by gato on January 2, 2022
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP