Sou bastante novo em engenharia de software e, como exercício de aprendizado, escrevi um jogo de xadrez. Meu amigo deu uma olhada e apontou que meu código parecia
for (int i = 0; i < 8; i++){
for (int j = 0; j < 8; j++){
enquanto ele insistia que deveria ser
for (int i = 0; i < CHESS_CONST; i++){
for (int j = 0; j < CHESS_CONST; j++){
com um nome de símbolo melhor no qual não posso me preocupar em pensar agora.
Agora, é claro, eu sei geralmente evitar usar números mágicos, mas sinto que desde
- esse número nunca mudará;
- o nome não poderia ser tão descritivo de qualquer maneira, já que o número é usado em muitos lugares ao longo do código; e
- qualquer pessoa que passe pelo código-fonte de um programa de xadrez deve saber o suficiente sobre xadrez para saber para que serve o 8,
realmente não há necessidade de uma constante simbólica.
Então, o que vocês acham? Isso é um exagero, ou devo apenas ir à convenção e usar um símbolo?
coding-style
coding-standards
chocolatedevil
fonte
fonte
i
ej
para as variáveis de loop. Durante toda a minha vida, não consigo descobrir qual deve representar a classificação e qual deve representar o arquivo. As classificações variam de 1..8 e os arquivos variam de a..h, mas no seu caso, ambosi
ej
de 0..7, de modo que não me ajuda a ver qual é qual. Existe alguma crise internacional de falta de cartas que eu não conheça, ou o que há de errado em renomeá-lasrank
efile
?foreach(var rank in Ranks)
. Também consideraria mesclar os dois loops em um onde cada elemento é uma tupla (classificação, arquivo).Respostas:
IMHO seu amigo está certo ao usar um nome simbólico, embora eu ache que o nome deve ser definitivamente mais descritivo (como em
BOARD_WIDTH
vez deCHESS_CONST
).Mesmo quando o número nunca muda durante a vida útil do programa, pode haver outros lugares no programa em que o número 8 ocorrerá com um significado diferente. Substituir "8" por
BOARD_WIDTH
qualquer que seja a largura da placa e usar outro nome simbólico quando outra coisa significa torna esses significados explícitos, óbvios e seu programa geral mais legível e fácil de manter. Ele também permite que você faça uma pesquisa global em seu programa (ou uma pesquisa de símbolo reverso, se o ambiente o fornecer), caso seja necessário identificar rapidamente todos os locais no código que dependem da largura da placa.Veja também este post anterior do SE.SE para uma discussão sobre como (ou não) escolher nomes para números.
Como uma observação lateral, uma vez que foi discutido aqui nos comentários : se, no código do seu programa real, importa se a variável
i
se refere a linhas ej
colunas do quadro, ou vice-versa, é recomendável escolher nomes de variáveis que faça a distinção clara, comorow
ecol
. O benefício de tais nomes é que eles fazem o código errado parecer errado.fonte
Ok, aqui estão alguns comentários que tenho:
Livrar-se dos números mágicos é uma ótima idéia. Existe um conceito conhecido como DRY, que geralmente é deturpado, mas a idéia é que você não duplique o conhecimento dos conceitos em seu projeto. Portanto, se você tiver uma classe chamada ChessBoard, poderá manter uma constante chamada BOARD_SIZE ou ChessBoard.SIZE anexada a ela. Dessa forma, existe uma única fonte para essas informações. Além disso, isso ajuda a legibilidade mais tarde:
Mesmo que o número nunca mude, seu programa é sem dúvida melhor. Qualquer pessoa que o leia sabe mais informações sobre o que o código está fazendo.
Um nome ruim é pior que nenhum nome, mas isso não significa que algo não deve ser nomeado. Apenas mude o nome. Não jogue fora o bebê com a água do banho. : p O nome pode ser descritivo, desde que você entenda bem o que está descrevendo. Então, esse conceito pode ser usado para várias coisas diferentes.
fonte
O que você realmente deseja é eliminar as referências ad nauseum às constantes, sejam elas nomeadas ou nuas:
Se você realmente proliferar a constante repetindo esses loops e outros enfeites, é melhor ficar com ele
8
.8
é auto-descritivo; não é uma macro que representa outra coisa.Você nunca vai transformá-lo em um programa de xadrez 9x9 e, se o fizer, a proliferação de 8 não será a maior dificuldade.
Podemos pesquisar uma base de código de 150.000 linhas para o token 8 e classificar quais ocorrências significam o que em segundos.
Muito mais importante é modularizar o código para que o conhecimento do xadrez se concentre no menor número de lugares possível. É melhor ter um, dois, talvez três módulos específicos de xadrez nos quais ocorra um 8 literal, do que trinta e sete módulos ligados a responsabilidades específicas de xadrez, referindo-se a 8 através de um nome simbólico.
Quando ou se essa constante se tornar uma fonte de tensão em seu programa, você poderá corrigi-lo facilmente naquele momento. Corrija problemas reais que estão acontecendo agora. Se você não sente que está sendo prejudicado por esse 8 em particular, siga esse instinto.
Suponha que no futuro você queira oferecer suporte a dimensões alternativas da placa. Nesse caso, esses loops terão que mudar se eles usam uma constante nomeada ou
8
, porque as dimensões serão recuperadas por alguma expressão comoboard.width
eboard.height
. Se você tiver, emBOARD_SIZE
vez de8
, esses lugares serão mais fáceis de encontrar. Então isso é menos esforço. No entanto, você não deve esquecer-se sobre o esforço de substituir8
comBOARD_SIZE
em primeiro lugar. O esforço geral não é menor. Fazer uma passagem sobre o código para alterar8
eBOARD_SIZE
, depois, outra para dar suporte a dimensões alternativas, não é mais barato do que apenas passar8
para o suporte de dimensão alternativa.Também podemos analisar isso a partir de uma análise de risco / benefício puramente fria e objetiva. O programa tem constantes nuas agora. Se estes são substituídos por uma constante, não há benefício; o programa é idêntico. Com qualquer alteração, há um risco diferente de zero. Nesse caso, é pequeno. Ainda assim, nenhum risco deve ser assumido sem um benefício. Para "vender" a mudança em face desse raciocínio, temos a hipótese de um benefício: um benefício futuro que ajudará em um programa diferente: uma versão futura do programa que não existe agora. Se um programa desse tipo estiver sendo planejado, essa hipótese e seu raciocínio associado são de boa-fé e devem ser levados a sério.
Por exemplo, se você está a dias de adicionar mais código que proliferará ainda mais essas constantes, convém acabar com elas. Se essas instâncias das constantes são aproximadamente todas as instâncias que existirão, por que se preocupar?
Se você trabalhar em software comercial, os argumentos de ROI também serão aplicados. Se um programa não estiver sendo vendido e a alteração de alguns números codificados para constantes não melhorar as vendas, você não será compensado pelo esforço. A mudança tem retorno zero sobre o investimento de tempo. Os argumentos de ROI generalizam além do dinheiro. Você escreveu um programa, investindo tempo e esforço, e conseguiu algo com isso: esse é seu retorno, seu "R". Se, ao fazer essa alteração sozinha, você obtém mais desse "R", seja o que for, então, por todos os meios. Se você tem algum plano para desenvolvimento adicional, e essa alteração melhora o seu "R", o mesmo. Se a mudança não tiver um "R" imediato ou previsível para você, esqueça.
fonte
8
NÃO é tão auto-descritivo, é um número que pode significar qualquer coisa. E talvez eles queiram fazer um jogo de xadrez 9x9, por que não? Se você tem 150.000 linhas de código, não há como memorizar o que cada um8
significa no código e, mesmo que pudesse, por que você faria? Isso é apenas um monte de problemas extras. No que diz respeito à modularização, substituir8
por algo comoNUM_RANKS
não prejudica a modularidade, na verdade, ajuda porque torna o código mais fácil de mexer.8
comBOARD_SIZE
, em primeiro lugar" - O tempo que você tinha passado examinando ao longo do seu código tentando descobrir o que cada um8
faz em seus meses de programa a partir de agora provavelmente exceder o tempo gasto substituir8
com uma constante significativa no nível do módulo.