Está usando nomes de parâmetros que diferem dos nomes de tipos apenas por maiúsculas e minúsculas considerados uma má prática em C #?

43

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

public Range PadRange(Range range) {}

Esse método usa um intervalo e retorna um novo intervalo que teve algum preenchimento aplicado. Então, dado o contexto genérico, não consigo pensar em um nome mais descritivo para o parâmetro. No entanto, eu me lembro de uma dica que eu peguei quando li o Code Complete sobre "distância psicológica". Diz

Psychological distance can be defined as the ease in which two items can be differentiated...As you debug, be ready for the problems caused by insufficient psychological distance between similar variable names and between similar routine names. As you construct code, choose names with large differences so that you can avoid the problem.

Minha assinatura de método tem um monte de "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) {}

Eu pessoalmente tenho um strong desgosto por esta convenção. Adicionar um prefixo "my" aos nomes das variáveis não fornece contexto adicional.

Eu também vejo o seguinte

public Range PadRange(Range rangeToPad) {}

Eu gosto mais do que o prefixo "meu", mas ainda não me importo com isso. Apenas parece excessivamente detalhado para mim, 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 definido, 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 fazendo a mim mesmo ou a futuros desenvolvedores um desserviço com essa convenção? Estou violando uma prática recomendada?

    
por Jason Tyler 19.04.2018 / 17:41
fonte

7 respostas

100

Não pense demais, Range range está bem. Eu uso esse tipo de nomenclatura por mais de 15 anos em C #, e provavelmente muito mais em C ++, e nunca tive nenhuma desvantagem real com isso, muito pelo contrário.

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

    
por 19.04.2018 / 17:45
fonte
17

Eu faço isso o tempo todo, isso me dá uma grande paz de espírito. Se for um argumento passado para um construtor que precisa ser atribuído a um membro, meu membro também seria chamado de intervalo e a atribuição seria

this.range = range;

Eu normalmente teria uma propriedade chamada Range.

Eles são todos a mesma coisa, apenas diferindo no contexto, então faz sentido manter um único nome e você terá que lembrar apenas um nome. É uma coisa, as diferenças são puramente técnicas.

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

Nota lateral do StyleCop

Controvérsia garantida!

Para aqueles que advogam contra o uso de "isso": Eu vi _, m, m_ e simplesmente nada. A própria linguagem está nos oferecendo uma maneira perfeitamente clara, inequívoca e universalmente reconhecível de indicar que estamos lidando com um membro da classe. Por que diabos você iria querer fazer o seu próprio caminho que mutila nomes já perfeitos?

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

"São mais personagens!" A sério? "O tempo de compilação vai disparar!" A sério? "Vou ter que levantar meu mindinho ao digitar!" Como se o tempo de digitação tivesse algum significado no tempo total de desenvolvimento.

Eu reconheço que qualquer estilo diferente do que você está acostumado a criar alguma oposição. Mas usar isso consistentemente é difícil de discutir. Aqui está como funciona para mim: antes de eu empurrar um novo arquivo de código, eu corro o StyleCop e ele vai encontrar um número de membros sem qualificadores "este". Eu coloquei "isso". na área de transferência, executado pelos membros e inserir. Nenhum esforço em tudo.

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

Se você é novo: geralmente faz você resmungar por uma semana ou duas e então você vai adorar.

    
por 19.04.2018 / 21:17
fonte
9

Minha auto-orientação sobre métodos de nomenclatura, 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 para o que elas são destinadas, não quais 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 é autoexplicativo.

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

Além disso, no corpo real do método, qualquer outra variável Range introduzida deve (deve) ser nomeada por sua intenção, portanto, você pode ter padded e unpadded ... toPad conforms para as convenções de nomenclatura, mas range apenas se destaca e não gelifica.

    
por 20.04.2018 / 08:22
fonte
3

Para nomear os elementos de código (tipos, variáveis, funções, qualquer coisa), a questão-chave a se perguntar é

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

O pior tipo de erro baseado em typo é aquele em que o código é compilado e executado, mas dá um comportamento diferente do que você espera, por razões que são 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 causando o problema e você poderá localizá-la e corrigi-la com facilidade.

Para sua situação em que o tipo e a variável diferem apenas na capitalização, esse sempre será o caso. (Ou quase sempre - com esforço suficiente, tenho certeza que você poderia fazer isso funcionar, mas você teria que realmente tentar.) Então eu acho que você está bem lá.

Onde você precisaria se preocupar seria se houvesse duas variáveis, métodos, funções ou propriedades no escopo atual chamadas range e Range . Nesse caso, o compilador provavelmente irá deixar passar, e você obterá um comportamento inesperado em tempo de execução. Note que são dois de qualquer desses tipos de elemento de código, não apenas "duas variáveis" ou "duas funções" - todas elas podem ser implicitamente convertidas umas nas outras, resultando em carnificina quando é executada. Você pode receber avisos, mas não pode garantir nada além disso. Você tem problemas semelhantes se tiver dois tipos declarados chamados range e Range .

Observe também que o mesmo se aplica ao estilo Notação húngara , em que os nomes são prefixados com um ou mais caracteres para dizer algo mais sobre o que quer que seja. Se você tiver uma variável chamada Range e um ponteiro para ela chamado PRange , será fácil acidentalmente perder a P , por exemplo. C # deve pegar isso, mas C e C ++ só vão te dar um aviso no máximo. Ou, o que é mais preocupante, suponha que você tenha uma versão dupla chamada DRange e reduziu a resolução para uma versão flutuante chamada FRange . Use o float por acidente (o que é fácil, já que as teclas são adjacentes em um teclado) e seu código funcionará , mas ele cairá de formas estranhas e imprevisíveis quando o processo acabar de resolução e underflows.

Não estamos mais nos dias em que estabelecemos limites de 8 caracteres ou 16 caracteres ou qualquer limite arbitrário. Às vezes, eu tenho ouvido novatos reclamando sobre nomes de variáveis mais longos, fazendo com que a codificação demore mais. São apenas novatos que reclamam disso. Programadores sérios sabem que o que realmente leva tempo é descobrir bugs obscuros - e a má escolha da nomenclatura é uma maneira clássica de se soltar naquele buraco em particular.

    
por 20.04.2018 / 12:51
fonte
1

Uma anedota que gostaria de adicionar, enquanto Range range é sintaticamente legal, pode tornar as coisas mais difíceis de depurar ou refatorar. Procurando por uma variável chamada "range" em um arquivo com muitas variáveis do tipo Range? Você pode acabar fazendo mais trabalho posteriormente como resultado dessa escolha de nomenclatura.

Isso é em grande parte dependente do contexto. Se for um arquivo de 30 linhas, minhas declarações realmente não entram em ação.

    
por 19.04.2018 / 23:53
fonte
1

Acho que você pode usar Range range nowdays por um motivo: realce de sintaxe. Os IDEs modernos geralmente destacam os nomes dos tipos e os nomes dos parâmetros em cores diferentes . Também um tipo e uma variável têm uma "distância lógica" considerável para não ser facilmente confundida.

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

    
por 20.04.2018 / 01:04
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 eu vi funções que executam uma função genérica com nomes de parâmetro que são específicos de forma enganosa. Como

public String removeNonDigits(String phoneNumber)

O nome da função soa muito genérico, como isso poderia ser aplicado a muitas seqüências de caracteres em muitas situações. Mas o nome do parâmetro é estranhamente específico, fazendo-me pensar se o nome da função é enganador ou ... o que?

Então, com certeza, em vez de dizer Intervalo de alcance, você pode dizer Intervalo de alcance ao Bolso. Mas que informação isto adiciona? Claro que é o intervalo para pad. O que mais poderia ser?

Adicionar algum prefixo arbitrário, "meu" ou "m_" ou qualquer outra coisa, transmite informações adicionais zero ao leitor. Quando eu usei linguagens onde o compilador não permite que um nome de variável seja o mesmo que um nome de tipo - com ou sem diferenciação de maiúsculas e minúsculas - eu às vezes coloco um prefixo ou um sufixo, apenas para fazê-lo compilar . Mas isso é apenas para satisfazer o compilador. Pode-se argumentar que, mesmo que o compilador possa distinguir, isso torna mais fácil para um leitor humano distinguir. Mas wow, em Java eu escrevi declarações como "Customer customer = new Customer ();" um bilhão de vezes e nunca achei confuso. (Eu sempre achei um pouco redundante e eu gosto disso em VB, você pode apenas dizer "dim cliente como novo cliente" e você não precisa dar o nome da classe duas vezes.)

Onde eu defendo strongmente os nomes genéricos é quando há duas ou mais instâncias do mesmo tipo na mesma função. ESPECIALMENTE parâmetros. Como:

public Range pad(Range range1, Range range2)

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

public boolean overlap(Range range1, Range range2)

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

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

    
por 22.04.2018 / 01:44
fonte