O uso de nomes de parâmetro que diferem dos nomes de tipo somente por maiúsculas e minúsculas é considerado uma prática ruim em C #?

43

Vejo perguntas semelhantes a essa com relação aos nomes de parâmetros que correspondem às propriedades da classe, mas não consigo encontrar nada sobre o uso de um nome de parâmetro igual ao nome do tipo de parâmetro, exceto por maiúsculas e minúsculas em C #. Não parece ser uma violação que eu possa encontrar, mas é considerada uma má prática? Por exemplo, eu tenho o seguinte método

public Range PadRange(Range range) {}

Esse método assume um intervalo e retorna um novo intervalo que teve algum preenchimento aplicado. Portanto, dado o contexto genérico, não consigo pensar em um nome mais descritivo para o parâmetro. No entanto, lembro-me de uma dica que recebi ao ler o código completo sobre "distância psicológica". Diz

A distância psicológica pode ser definida como a facilidade com que dois itens podem ser diferenciados ... Ao depurar, esteja preparado para os problemas causados ​​pela distância psicológica insuficiente entre nomes de variáveis ​​semelhantes e entre nomes de rotina semelhantes. Ao criar o código, escolha nomes com grandes diferenças para evitar o problema.

Minha assinatura de método tem muito "Range" acontecendo, então parece que pode ser um problema com relação a essa distância psicológica. Agora, vejo muitos desenvolvedores fazendo o seguinte

public Range PadRange(Range myRange) {}

Pessoalmente, tenho um forte desagrado por esta convenção. A adição de um prefixo "my" aos nomes de variáveis ​​não fornece contexto adicional.

Eu também vejo o seguinte

public Range PadRange(Range rangeToPad) {}

Gosto disso melhor do que o prefixo "my", mas ainda não me importo com isso no geral. Parece-me excessivamente detalhado e lê desajeitadamente como um nome de variável. Para mim, entende-se que o intervalo será preenchido por causa do nome do método.

Então, com tudo isso exposto, meu instinto é ir com a primeira assinatura. Para mim, está limpo. Não há necessidade de forçar o contexto quando não é necessário. Mas estou prestando um desserviço a mim ou a futuros desenvolvedores com esta convenção? Estou violando uma prática recomendada?

Jason Tyler
fonte
35
Se você não conseguir criar um parâmetro mais descritivo, tudo Range rangebem.
19418 Robert Harvey
21
Nessa situação, o IDE colorirá 'Range' e 'range' de maneira diferente, portanto é muito fácil ver que um é do tipo e um é um nome de variável.
17 de 26
10
Sim, eu lembro disso. Está em suas diretrizes de design como consideração. "CONSIDERA dar a uma propriedade o mesmo nome que seu tipo." docs.microsoft.com/en-us/dotnet/standard/design-guidelines/…
Jason Tyler
11
Também é bom: Range r(pelo menos para um corpo de método curto) e Range toPad.
Bergi
19
Eu sempre considerei o prefixo "meu" como algo que é feito no código de exemplo, onde é usado para indicar ao leitor que um nome deve ser alterado para outro, dependendo do contexto. Não é algo que realmente deve acabar em qualquer código real.
Kapex

Respostas:

100

Não pense demais, tudo Range rangebem. Uso esse tipo de nomeação há mais de 15 anos em C # e provavelmente muito mais em C ++, e nunca tive nenhuma desvantagem real com isso, muito pelo contrário.

Obviamente, quando você tem variáveis ​​locais diferentes no mesmo escopo, do mesmo tipo, provavelmente ajudará a investir algum esforço mental para distingui-las adequadamente.

Doc Brown
fonte
6
Outra exceção que eu adicionaria é quando a instância está executando uma ação específica. Há um pouco de espaço para ser mais descritivo do motivo pelo qual o parâmetro é necessário, por exemplo. Wack (Bozo bozoToBeWacked) Ainda mais se o parâmetro for opcional e descrever o que o objeto nesse cenário significa / o que afetará. Minha regra geral, se não for óbvio sem olhar para o código o que o parâmetro faz, ele precisará de um nome e / ou comentários melhores.
Mike
17
Eu consideraria Wack(Bozo bozoToBeWacked)um exemplo de redundância no nome da variável que é amplamente expressa pelo próprio método (e, portanto, indesejável pela pergunta original). Wack(Person bozo)é mais semanticamente valioso, no entanto, pois implica que se espera que apenas bozos sejam malucos.
Miral
2
No caso que você mencionou no segundo parágrafo, muitas vezes vou renomear o parâmetro para algo como initialRange. Ainda é muito genérico, mas não tem quase o mesmo nível de aversão que myRange.
21418
@Miral: Torna-se mais relevante em casos como Punch(Bozo punchingBozo, Bozo bozoToBePunched). A nomeação detalhada é mais relevante quando você precisa distinguir entre várias coisas (que são semanticamente descritas com praticamente as mesmas palavras). A sugestão de OP Range rangeToPadnão é necessária em seu exemplo de método de parâmetro único, mas pode ser incrivelmente necessária para um método que aceita vários Rangeobjetos.
quer
7
@Flater Punch(Bozo source, Bozo target)faria o trabalho #
Thomas Ayoub
17

Eu faço isso o tempo todo, isso está me dando uma grande tranqüilidade. Se for um argumento passado para um construtor que precisa ser atribuído a um membro, meu membro também será chamado de intervalo e a atribuição será

this.range = range;

E eu normalmente teria uma propriedade chamada Range.

Eles são todos iguais, diferindo apenas no contexto; portanto, faz sentido manter um único nome e você precisará lembrar apenas um nome. Uma coisa é que as diferenças são puramente técnicas.

Você deve ser rigoroso com membros totalmente qualificados com "isso". embora, mas é para isso que serve o StyleCop.

Nota lateral do StyleCop

Controvérsia garantida!

Para aqueles que advogam contra o uso de "isto": eu vi _, m, m_ e apenas nada. A própria linguagem está nos oferecendo uma maneira perfeitamente clara e inequívoca de reconhecimento universal de indicar que estamos lidando com um aluno. Por que diabos você gostaria de criar seu próprio caminho que mutila nomes já perfeitos?

A única razão pela qual consigo pensar que é um hábito herdado da era C, quando realmente fazia sentido fazê-lo, porque não havia outro caminho.

"São mais personagens!" A sério? "O tempo de compilação disparará!" A sério? "Terei que levantar meu mindinho ao digitá-lo!". Como se o tempo de digitação tivesse algum significado no tempo total de desenvolvimento.

Reconheço que qualquer estilo diferente do que você está acostumado suscitará alguma oposição. Mas usar isso de forma consistente é difícil de argumentar. Eis como funciona para mim: Antes de enviar um novo arquivo de código, eu corro o StyleCop e ele encontrará vários membros sem os qualificadores "this". Eu coloquei "isso". na área de transferência, execute pelos membros e insira. Nenhum esforço.

O StyleCop faz muito mais que isso (haha). Existem muitas maneiras pelas quais um desenvolvedor pode (considerando apenas a formatação do código) frustrar o trabalho de manutenção de seu sucessor. StyleCop impede a maioria deles. É inestimável.

Se você é novo: normalmente faz você se queixar por uma semana ou duas e então você vai adorar.

Martin Maat
fonte
19
" Você deve ser rigoroso com membros totalmente qualificados com" isto ".", -1. Não use, thisexceto quando essencial. Caso contrário, é apenas barulho. Use _rangepara o campo e thisnunca é necessário, exceto nos métodos de extensão.
David Arno
12
Concordo com @DavidArno. 'isso' é apenas ruído puro. 'Range' é uma propriedade, '_range' é um campo e 'range' é um parâmetro.
17 de 26
8
@ David Se a variável é um membro da classe, é essencial e supera qualquer prefixo arbitrário para sinalizar que você está olhando para um membro da classe em vez de um argumento ou variável local.
Martin Maat
6
Meu IDE dispararia bolas de fogo no segundo em que eu atribuiria uma variável a si mesma.
koekje
21
@DavidArno Gostaria de explicar por que o "ruído" de _é preferível ao ruído de this.? Eu diria que um tem um significado imposto pelo idioma (e normalmente possui destaque de sintaxe) enquanto o outro não.
Clint
9

Minha orientação pessoal sobre métodos de nomes, parâmetros e variáveis ​​é bastante simples:

  1. Se o nome contiver o tipo que está sendo passado ou retornado, você está fazendo errado.
  2. Nomeie as coisas pelo que elas se destinam, não o que são.
  3. Lembre-se sempre de que o código é lido mais do que está escrito.

Assim, a assinatura do método ideal, na minha opinião, seria:

Range Pad(Range toPad)

Encurtar o nome do método é auto-explicativo.

O nome do parâmetro toPadinforma imediatamente ao leitor que esse parâmetro provavelmente será modificado no local sendo preenchido e retornado. Por outro lado, nenhuma suposição pode ser feita sobre uma variável denominada range.

Além disso, no corpo real do método, quaisquer outras Rangevariáveis ​​introduzidas seriam (deveriam) nomeadas por suas intenções, para que você possa paddede unpadded... toPadesteja em conformidade com essas convenções de nomenclatura, mas rangeapenas se destaca e não gelifica.

Ian Kemp
fonte
3
padded/ unpaddedsoa bem para variáveis ​​locais imutáveis. Porém, se houver um toPadparâmetro mutável , depois que o preenchimento for concluído, o nome toPadnão se ajustará mais (a menos que o resultado seja retornado imediatamente). Eu preferiria manter-me Range rangenesses casos.
Kapex
@Kapep Eu chamaria isso apenas result. Ele é modificado e retornado . O último é claro a partir do nome e o primeiro segue, pois retornar um argumento não modificado não faz sentido.
Maaartinus 20/0418
A partir da assinatura, o Padmétodo retorna a Range. Isso, para mim, implica que o que eu passei será preservado, não modificado no local e um novo preenchido Rangeserá retornado. .
Aaron M. Eshbach
11
Não sei o que pensar dos seus conselhos. Pad(toPad)parece IMHO meio errado. Você faz um bom ponto de defender seu ponto de vista. Você recebe um +0 de mim! :)
Eric Duminil
Na questão, afirma que "retorna um novo intervalo que teve algum preenchimento aplicado". Concordo com a sua nomeação para o que você acha que o cenário é, mas para a questão real eu iria para algo como Faixa CreateRangeWithPadding (fonte Range)
Richard Willis
3

Para nomear elementos de código (tipos, variáveis, funções, qualquer coisa), a principal pergunta a ser feita é:

Se eu digitar um erro de digitação, o compilador encontrará para mim?

O pior tipo de erro baseado em erros de digitação é aquele em que o código compila e executa, mas oferece um comportamento diferente do esperado, por motivos sutis. E como é devido a um erro de digitação, geralmente é muito difícil ver quando você está inspecionando o código. Se um erro de digitação interromper a compilação do código, o compilador sinalizará a linha que está causando o problema e você poderá encontrá-lo e corrigi-lo facilmente.

Para sua situação em que o tipo e a variável diferem apenas em letras maiúsculas, esse sempre será o caso. (Ou quase sempre - com esforço suficiente, tenho certeza de que você poderia fazê-lo funcionar, mas você precisaria realmente tentar.) Portanto, acho que você está bem por lá.

Onde você precisaria se preocupar seria se houvesse duas variáveis, métodos, funções ou propriedades no escopo atual chamado rangee Range. Nesse caso, o compilador provavelmente vai deixá-lo passar, e você está indo para obter um comportamento inesperado em tempo de execução. Note-se que isso é dois de qualquer um desses tipos de elemento de código, não apenas "duas variáveis" ou "duas funções" - todos esses podem ser expressos implicitamente uns aos outros, resultando em carnificina quando ele é executado. Você pode receber avisos, mas não pode garantir nada além disso. Você tem problemas semelhantes se tiver dois tipos declarados chamados rangee Range.

Observe também que o mesmo se aplica ao estilo de notação húngaro , onde os nomes são prefixados com um ou mais caracteres para dizer algo mais sobre o que quer que seja. Se você tem uma variável chamada Rangee um ponteiro para ela PRange, é fácil perder acidentalmente a P, por exemplo. O C # deve capturar isso, mas o C e o C ++ fornecerão apenas um aviso no máximo. Ou, o que é mais preocupante, suponha que você tenha uma versão dupla chamada DRangee faça um downsample para uma versão flutuante chamada FRange. Use o flutuador por acidente (o que é fácil, já que as chaves são adjacentes em um teclado) e seu código será tipo de trabalho, mas vai cair de forma estranha e imprevisíveis quando o processo é executado fora de resolução e underflows.

Já não estamos nos dias em que tínhamos limites de nomeação de 8 ou 16 caracteres ou qualquer limite arbitrário. Às vezes, ouvi novatos reclamando de nomes de variáveis ​​mais longos, tornando a codificação mais demorada. Porém, são apenas os novatos que reclamam disso. Os codificadores sérios sabem que o que realmente leva tempo é descobrir bugs obscuros - e a má escolha de nomear é uma maneira clássica de mergulhar nesse buraco em particular.

Graham
fonte
Apenas uma nota para os leitores - para C #, as pessoas devem realmente evitar a notação húngara. Embora fosse útil em tempos antigos, quando o destaque da sintaxe não era uma coisa ou era limitado, hoje em dia realmente não ajuda.
T. Sar - Restabelece Monica
@ T.Sar Mesmo naquela época, eu odiava com paixão! Como você diz, IDEs melhores resolveram os problemas para os quais foram direcionados, mas ainda aparecem de vez em quando. Você ainda o verá se precisar conversar com a API do Windows, por exemplo, por razões históricas. Eu não queria estragar totalmente os estilos preferidos das pessoas, se elas realmente gostassem, mas queria usá-las como um gancho para mostrar que letras maiúsculas / minúsculas não é a única maneira de estragar os nomes.
Graham20
Estou ciente de que você não está propondo o uso da notação húngara, mas também estou ciente de que os desenvolvedores jovens têm uma enorme fraqueza por coisas com nomes legais. Ser capaz de dizer "Meu código está escrito neste estilo super secreto de codificação ninja - a Notação Húngara!" pode parecer irresistivelmente legal para as mentes mais jovens. Eu já vi muitos desenvolvedores serem vítimas do hype de palavras legais ... Notação húngara é dor, dê a forma do código-fonte xX
T. Sar - Reinstate Monica
@ T.Sar É verdade. "Quem não se lembra do passado está fadado a repeti-lo" e tudo isso. : /
Graham
11
Estamos falando da notação húngara original ou de como ela foi mal interpretada pela Microsoft (perto de "os escritores de documentação da equipe do Windows inventaram inadvertidamente o que ficou conhecido como Sistemas Húngaro" e também na entrevista de Joel Spolsky por Leo Laporte no episódio Triangulation 277, 12/12/2016, 04 min. 00 seg. - 06 min. 35 seg. )?
Peter Mortensen
1

Uma anedota que gostaria de acrescentar, embora Range rangeseja sintaticamente legal, pode tornar as coisas mais desafiadoras para depurar ou refatorar. Procurando por aquela variável chamada "range" em um arquivo com muitas variáveis ​​do tipo Range? Você pode acabar fazendo mais trabalhos posteriormente, como resultado dessa opção de nomeação.

Isso depende muito do contexto. Se for um arquivo de 30 linhas, minhas declarações não entram em jogo.

Jacob M.
fonte
7
A maioria das pessoas usa ferramentas que distinguem entre tipos e parâmetros ou variáveis ​​para o desenvolvimento do Windows. O que você descreve me lembra os bons e velhos dias do grep no Unix.
Frank Hileman
11
@FrankHileman Pode surpreendê-lo, mas o Unix ainda está vivo e o grep ainda está em uso (: D). Como o grep diferencia maiúsculas de minúsculas, o problema mencionado simplesmente não existe. No entanto, mesmo nós, haters de janelas viciados em terminal, raramente usamos grep para código-fonte, pois o IDE é muito melhor em pesquisas comuns.
Maaartinus 20/0418
Penso que concordamos que a plataforma não é o ponto. grepé uma ótima ferramenta, mas não é uma ferramenta de refatoração. E existem ferramentas de refatoração em todas as plataformas de desenvolvimento que eu usei. (OS X, Ubuntu, Windows).
Eric Wilson
@EricWilson Ao mesmo tempo, grep e sed eram as únicas ferramentas de refatoração no unix.
precisa saber é o seguinte
@FrankHileman Só porque algo é usado como uma ferramenta de refatoração não significa que ele seja um. Posso refatorar no bloco de notas, mas isso não o torna mais do que um editor de texto.
Eric Wilson
1

Eu acho que você pode usar os dias de Range rangehoje por um motivo: destaque da sintaxe. Os IDEs modernos geralmente destacam os nomes dos tipos e dos parâmetros em cores diferentes . Além disso, um tipo e uma variável têm uma considerável "distância lógica" que não deve ser facilmente confundida.

Se esse não fosse o caso, consideraria um nome diferente ou tentaria ativar um plug-in / extensão que possa destacar essa sintaxe.

akaltar
fonte
0

Quando uma função é genérica, é lógico que os parâmetros serão genéricos e, portanto, devem ter nomes genéricos.

Não é o que você está dizendo, mas vi funções que executam uma função genérica que têm nomes de parâmetros que são enganosamente específicos. Gostar

public String removeNonDigits(String phoneNumber)

O nome da função parece muito genérico, pois isso pode ser aplicado a muitas seqüências de caracteres em várias situações. Mas o nome do parâmetro é estranhamente específico, me fazendo pensar se o nome da função é enganoso, ou ... o quê?

Então, ao invés de dizer Range range, você pode dizer Range rangeToPad. Mas que informações isso adiciona? Claro que é a faixa a ser preenchida. O que mais poderia ser?

Adicionar algum prefixo arbitrário, "meu" ou "m_" ou qualquer outra coisa, transmite zero informações adicionais ao leitor. Quando eu usei idiomas nos quais o compilador não permite que o nome de uma variável seja igual ao nome do tipo - com ou sem distinção entre maiúsculas e minúsculas -, às vezes coloco um prefixo ou sufixo, apenas para compilar . Mas isso é apenas para satisfazer o compilador. Alguém poderia argumentar que, mesmo que o compilador possa distinguir, isso facilita a distinção de um leitor humano. Mas uau, em Java, escrevi declarações como "Customer customer = new Customer ();" um bilhão de vezes e eu nunca achei isso confuso. (Eu sempre achei isso um pouco redundante e gosto bastante disso no VB, você pode dizer "cliente fraco como novo cliente" e não precisa dar o nome da classe duas vezes).

Onde eu objeto fortemente a nomes genéricos é quando há duas ou mais instâncias do mesmo tipo na mesma função. ESPECIALMENTE parâmetros. Gostar:

public Range pad(Range range1, Range range2)

Qual é a diferença entre range1 e range2? Como eu vou saber? Se é algo em que realmente são dois valores genéricos e intercambiáveis, tudo bem, como

public boolean overlap(Range range1, Range range2)

Eu esperaria que retornasse true se os intervalos se sobrepuserem e false se não o fizerem, portanto eles são genéricos e intercambiáveis.

Mas se eles são diferentes, me dê uma pista de como eles são diferentes! Eu estava trabalhando recentemente em um programa que tinha uma classe "Place" para armazenar dados sobre locais geográficos e com variáveis ​​desse tipo chamadas "p", "place", "place2", "myPlace" etc. Uau, essas nomes realmente me ajudam a determinar qual é qual.

Jay
fonte