Este uso de um exagero constante simbólico?

34

Sou relativamente novo em engenharia de software e, como exercício de aprendizagem, 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 algum nome de símbolo melhor que eu não posso me incomodar em pensar agora.

Agora, é claro, eu geralmente evito usar números mágicos, mas eu sinto que desde

  1. esse número nunca será alterado;
  2. o nome não poderia ser tão descritivo, pois o número é usado em muitos lugares ao longo do código; e
  3. qualquer um que esteja passando pelo código-fonte de um programa de xadrez deve saber o suficiente sobre o 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 com a convenção e usar um símbolo?

    
por chocolatedevil 08.04.2017 / 09:43
fonte

3 respostas

102

IMHO seu amigo está certo em usar um nome simbólico, embora eu ache que o nome definitivamente deveria ser mais descritivo (como BOARD_WIDTH em vez de CHESS_CONST ).

Mesmo quando o número nunca muda durante a vida útil do programa, pode haver outros locais em seu programa em que o número 8 ocorrerá com um significado diferente. Substituir "8" por BOARD_WIDTH , sempre que a largura da placa é significada, e usar outro nome simbólico quando uma coisa diferente é significada torna explícitos esses significados diferentes, óbvios e seu programa geral mais legível e sustentável. Ele permite que você também faça uma pesquisa global sobre seu programa (ou uma busca de símbolo reverso, se o seu ambiente fornecer) no caso de você precisar identificar rapidamente todos os locais no código que dependem da largura da placa.

Veja também este antigo post do SE.SE para uma discussão sobre como (ou como não) escolher nomes para números.

Como uma observação, uma vez que foi discutido aqui nos comentários : se, no código do seu programa real, é importante que a variável i se refira a linhas e j às colunas de a placa, ou vice-versa, é recomendável escolher nomes de variáveis que tornem a distinção clara, como row e col . O benefício de tais nomes é que eles fazem o código errado parecer errado.     

por 08.04.2017 / 09:56
fonte
10

Ok, aqui estão alguns comentários que tenho:

Livrar-se de números mágicos é uma ótima idéia. Existe um conceito conhecido como DRY, que é muitas vezes deturpado, mas a ideia é que você não duplique o conhecimento dos conceitos em seu projeto. Então, se você tem uma classe chamada ChessBoard, você pode manter uma constante chamada BOARD_SIZE ou ChessBoard.SIZE anexada a ela. Desta forma, existe uma única fonte para essa informação. Além disso, isso ajuda na legibilidade mais tarde:

for (int i = 0; i < ChessBoard.SIZE; i++){
  for (int j = 0; j < ChessBoard.SIZE; j++){

Mesmo que o número nunca mude, seu programa é possivelmente melhor. Qualquer pessoa que esteja lendo sabe mais informações sobre o que o código está fazendo.

Um nome ruim é pior do que nenhum nome, mas isso não significa que algo não deva 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.

    
por 08.04.2017 / 16:28
fonte
-7

O que você realmente quer é eliminar as referências ad nauseum às constantes, sejam elas nomeadas ou nuas:

for_each_chess_square (row, col) {
  /*...*/
}

Se você realmente vai proliferar a constante repetindo esses loops e outros enfeites, é melhor ficar com 8 .

8 é autodescritivo; não é uma macro que significa outra coisa.

Você nunca vai (TM) transformá-lo em um programa de xadrez 9x9 e se você fizer isso, 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 em segundos.

Muito mais importante é modularizar o código de modo que o conhecimento sobre o xadrez esteja concentrado no menor número de lugares possível. É melhor ter um, dois, talvez três módulos específicos de xadrez em que um 8 literal ocorre, do que trinta e sete módulos atados com responsabilidade específica do xadrez, referindo-se a 8 através de um nome simbólico.

Quando ou se esta 8 constante se tornar uma fonte de tensão em seu programa, você poderá corrigi-la facilmente nesse momento. Corrigir problemas reais que estão acontecendo agora. Se você não sentir que está sendo prejudicado por esse 8 em particular, siga esse instinto.

Suponha que, no futuro, você queira oferecer suporte a dimensões de placas alternativas. Nesse caso, esses loops precisarão mudar se usarem uma constante nomeada ou 8 , porque as dimensões serão recuperadas por alguma expressão como board.width e board.height . Se você tiver BOARD_SIZE em vez de 8 , esses locais serão mais fáceis de encontrar. Então isso é menos esforço. No entanto, você não deve esquecer o esforço de substituir 8 por BOARD_SIZE em primeiro lugar. O esforço geral não é menor. Fazer uma passagem sobre o código para alterar 8 para BOARD_SIZE e, em seguida, outro para suportar dimensões alternativas, não é mais barato do que ir de 8 para suporte a dimensões alternativas.

Também podemos observar isso a partir de uma análise de riscos / benefícios puramente fria e objetiva. O programa tem nuas constantes 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. Neste caso, é pequeno. Ainda assim, nenhum risco deve ser tomado sem um benefício. Para "vender" a mudança em face desse raciocínio, temos que supor um benefício: um benefício futuro que ajudará com um programa diferente: uma versão futura do programa que não existe agora. Se tal programa está sendo planejado, esta hipótese e seu raciocínio associado são bona fide e devem ser levados a sério.

Por exemplo, se você estiver a poucos dias de adicionar mais códigos que proliferam ainda mais essas constantes, convém eliminar esses códigos. Se essas instâncias das constantes forem aproximadamente todas as instâncias que existirão, então por que se preocupar?

Se você já trabalhou em software comercial, os argumentos de ROI também serão aplicados. Se um programa não está vendendo e a alteração de alguns números codificados para constantes não melhora as vendas, você não será compensado pelo esforço. A mudança tem zero retorno sobre o investimento de tempo. Argumentos de ROI generalizam além do dinheiro. Você escreveu um programa, investindo tempo e esforço, e conseguiu algo a partir disso: esse é o seu retorno, o seu "R". Se fazendo essa mudança sozinho, você obtém mais do que "R", seja o que for, então por todos os meios. Se você tem algum plano para desenvolvimento adicional, e essa mudança melhora seu "R", idem. Se a mudança não tiver um "R" imediato ou previsível para você, esqueça.

    
por 08.04.2017 / 17:54
fonte