Argumentos nomeados (parâmetros) como um auxílio à legibilidade

11

Há muito tempo, eu programava muito no ADA, e era normal nomear argumentos ao invocar uma função - SomeObject.DoSomething (SomeParameterName => someValue);

Agora que o C # suporta argumentos nomeados, estou pensando em voltar a esse hábito em situações em que talvez não seja óbvio o que um argumento significa.

Você pode argumentar que sempre deve ser óbvio o que um argumento significa, mas se você tiver um argumento booleano e os chamadores estiverem passando em "verdadeiro" ou "falso", qualificar o valor com o nome torna o site da chamada mais legível.

contentFetcher.DownloadNote (nota, manual: true);

Eu acho que eu poderia criar enums em vez de usar verdadeiro ou falso (manual, automático neste caso).

O que você pensa ocasionalmente usando argumentos nomeados para facilitar a leitura do código?

Damian
fonte
O comentário de parâmetro sobre os métodos também ajuda.
Amir Rezaei
1
@ amir-rezaei: Os comentários dos parâmetros sobre os métodos só ajudam se você puder confiar nos comentários. A menos que você tenha bons desenvolvedores e bons processos de revisão de código, eu não confiaria nos comentários.
btilly
Como usuário ada de uma vez, sou para uso ocasional, como você descreve. É assim que eu lembro deles sendo usados ​​em Ada, BTW - eu não chamaria de "anormal", mas a palavra "normal" parece implicar que a maioria das chamadas especificaria nomes de parâmetros, e não é assim que eu lembro das coisas. É claro que as convenções variam, mas a confusão desnecessária é uma má convenção em qualquer idioma da IMO.
31311 Steve314
Concordo com seu uso no Ada - não foi algo que fizemos o tempo todo, mas onde ajudou.
Damian

Respostas:

7

Isso foi sugerido no desenvolvimento do C ++, e Stroustrup discute isso em seu "Design e evolução do C ++", páginas 153 e seguintes. A proposta foi bem elaborada e baseou-se em experiências anteriores com a Ada. Não foi adotado.

O maior motivo foi que ninguém queria incentivar funções com um grande número de parâmetros. Cada recurso adicional em um idioma custa algo e não havia desejo de adicionar um recurso para facilitar a gravação de programas ruins.

Também levantou questões sobre quais eram os nomes de parâmetros canônicos, particularmente na convenção usual de cabeçalho e arquivo de código. Algumas organizações tinham nomes de parâmetro mais longos e mais descritivos no arquivo .h, e nomes mais curtos e fáceis de digitar no arquivo .cpp (sufixos de arquivo substitutos, conforme desejado). Exigir que esses sejam os mesmos seria um custo adicional na compilação, e a mistura de nomes entre os arquivos de origem pode causar erros sutis.

Também pode ser manipulado usando objetos em vez de chamadas de função. Em vez de uma chamada GetWindow com uma dúzia de parâmetros, crie uma classe Window com uma dúzia de variáveis ​​privadas e adicione setters conforme necessário. Ao encadear os levantadores, é possível escrever algo parecido my_window.SetColor(green).SetBorder(true).SetBorderSize(3);. Também é possível ter funções diferentes com padrões diferentes que chamam a função que realmente faz o trabalho.

Se você está preocupado apenas com o efeito da documentação contentFetcher.DownloadNote(note, manual : true);, sempre pode escrever algo como contentFetcher.DownloadNote(note, /* manual */ true);, portanto, isso não ajuda muito na documentação.

David Thornley
fonte
Curiosamente, quando mudei de Ada para C, comecei a usar a convenção que você descreve - os revisores de código odiavam isso. Concorde em não usá-lo para um grande número de parâmetros.
Damian
7

Eu acho que isso é questão de tornar o código incorreto mais legível, em vez de "melhores práticas".

Ter um método (ou contratado) que aceite 20 parâmetros é um "mau cheiro" e provavelmente deve-se a um problema no seu projeto. No entanto, se eu sou forçado a trabalhar no código quando os métodos usam muitos parâmetros, o parâmetro nomeado torna o código menos difícil de entender.

Quando os métodos possuem apenas 1 ou 2 parâmetros e, a partir do nome do método, fica claro qual é o parâmetro, o parâmetro nomeado não adiciona nada. Este é o caso ideal para se estar.

Se todo o código no qual você trabalha for escrito como o livro " código limpo ", você terá muito pouco uso para parâmetros nomeados, no entanto, vivemos no mundo real.

Ian
fonte
1
Uma função com dois parâmetros pode ser confusa, se os dois parâmetros forem do mesmo tipo e sem nenhuma pista de qual é qual. É claro que você pode nomear a função de uma maneira que forneça essa pista, mas na verdade você está apenas fazendo o que os nomes de parâmetro fazem de qualquer maneira - exceto que você torna obrigatório incluir essa verbosidade mesmo quando o contexto (por exemplo, as expressões que fornecem o parâmetro parâmetros) tornam óbvio qual parâmetro é qual.
31311 Steve314
1
@ Steve314 Exemplo:void TrackDataChange(Data oldData, Data newData)
Alexander
3

Concordo que adicionar o nome do parâmetro o torna mais legível. No entanto, a maioria dos livros que li parece considerar as opções booleanas uma prática ruim. Às vezes faço isso:

public Content DownloadNote(Note note)
{
    return downloadNote(note, manual: false);
}

public Content DownloadNoteManually(Note note)
{
    return downloadNote(note, manual: true);
}

Isso oferece mais flexibilidade ao implementar sua API. Também permite controlar o caso em que você tem várias opções booleanas, mas nem todas elas podem estar ativas ao mesmo tempo.

Scott Whitlock
fonte
3
Se você tiver x opções, fará 2 ^ x frontends?
apoorv020
@ apoorv020 - se eu tivesse parâmetros suficientes para uma chamada de método que 2 ^ x se tornassem significativos, eu criaria uma nova classe para armazenar os valores dos parâmetros e passar apenas um parâmetro.
Scott Whitlock,
@ scott-whitlock: Opção 1 - crie um objeto, defina x propriedades, chame um método uma vez com seu objeto. Opção 2 - chame um método com x parâmetros nomeados. Qual é o melhor depende do seu idioma. Em uma linguagem de tipo dinâmico, a opção 1 requer significativamente mais caldeira sem ganho e, portanto, é pior. Em um idioma estaticamente digitado, você ainda adiciona o padrão, mas os testes para chaves nomeadas incorretamente são executados em tempo de compilação, em vez de em tempo de execução. Portanto, a opção 1 é melhor em C #, mas a opção 2 é uma vitória clara em Python.
btilly
@btilly - como Ian apontou, o Clean Code diz claramente para você não ter funções com mais de 2 ou 3 parâmetros. Para ser justo, tratava-se de Java, que é estaticamente digitado. O OP também está perguntando sobre C #, que é estaticamente digitado. Eu ainda preferiria usar sobrecargas de função e / ou nomes de funções com nomes precisos diferentes do que uma longa lista de parâmetros.
Scott Whitlock,
@ scott-whitlock: Nós realmente discordamos? Concordamos sobre o que é melhor em C #. Nós dois sabemos o que o Código Limpo diz. Meu argumento foi que é importante entender por que isso é bom, para que você saiba quando o conselho se encaixa ou não em um ambiente diferente.
btilly
3

Eu acredito muito em parâmetros nomeados em situações em que os tipos e semânticas não são claros no nome do método. Minha experiência é que poucas pessoas leem a documentação.

Dito isto, os parâmetros nomeados não devem ser uma alternativa para criar listas de argumentos sensatas, usar objetos auxiliares (para "unir" argumentos semanticamente relacionados) e usar enumerações quando relevante.

Uri
fonte
0

Eu acho que isso é mais útil em linguagens não OO, onde você pode ter uma função que precisa fazer algo de várias maneiras ligeiramente diferentes, e a maneira como ela determina o que fazer é baseada nos valores dos parâmetros. No mundo OOP, sobrecarregaríamos a função, mas quando isso não for possível, você acaba passando um monte de sinalizadores (ou um monte de valores, e se eles são ou não passados ​​é o sinalizador).

Eu acho que é mais legível, até certo ponto; mas como outros já mencionaram, ter muitos parâmetros é um cheiro de código, por isso não vejo muito uso para isso em uma linguagem orientada a objetos como C #.

TMN
fonte