Então, todo número no código que estamos enviando para um método como argumento é considerado um Número Mágico? Para mim, não deveria. Eu acho que se algum número é digamos que é para um tamanho mínimo de nome de usuário e começamos a usar "6" no código ... então sim, temos um problema de manutenção e aqui "6" é um número mágico ... mas se estamos chamando um método que um de seus argumentos aceita um número inteiro, por exemplo, como o i-ésimo membro de uma coleção e depois passamos "0" para essa chamada de método, nesse caso, não vejo esse "0" como uma mágica número. O que você acha?
programming-practices
Blake
fonte
fonte
Respostas:
Se o significado do número é muito claro no contexto, não acho que seja um problema de "número mágico".
Exemplo: digamos que você esteja tentando obter a substring de uma string, desde o início até algum token, e o código se parece com isso (linguagem e biblioteca imaginárias):
Nesse contexto, o significado do número 0 é claro o suficiente. Suponho que você possa definir
START_OF_SUBSTRING
e defini-lo como 0, mas, neste caso, acho que seria um exagero (embora seja a abordagem correta se você soubesse que o início de sua substring pode não ser 0, mas isso depende das especificidades de sua situação).Outro exemplo pode ser se você estiver tentando determinar se um número é par ou ímpar. Escrita:
não é tão estranho quanto:
Testando números negativos como
também me parece estranho, eu prefiro ver
fonte
360
para marcar uma rotação completa com o entendimento de que a maioria das pessoas saberá o que isso significa (embora isso é um caso em que não seria ferido para fornecer uma constante)0
no contexto do meu exemplo de substring. Nesse caso, essa pode ser a menor quantidade de dano que eles podem causar. Faz muito tempo desde que eu fiz qualquer codificação que fizesse cálculos geométricos, mas geralmente os valores 15, 30, 45, 60, 90, 180, 360 eram constantes que foram aceitas. Eu nunca vi ninguém definirFIFTEEN_DEGREES
, ...É óbvio que zero significa ausência. Acho 0 mais fácil de entender do que uma variável chamada "ausênciaValor".
É óbvio que 0 é a posição inicial. Eu ficaria confuso com uma variável chamada "firstPosition". Essa variável me faria pensar se a posição inicial poderia mudar.
fonte
Sugiro três fatores principais para decidir se algo deve ser uma declaração constante:
Algo como pi provavelmente deve ser escrito como uma constante nomeada, e não como um literal numérico, uma vez que um literal numérico pode ser desnecessariamente detalhado, impreciso ou ambos. Algo como o número de slots em um cache provavelmente deve ser uma constante nomeada (embora veja a nota abaixo) para permitir a possibilidade de expandir o cache sem precisar modificar todo o código que o usa. Coisas como os números "4", "28" e "29" na declaração
if ((year % 4)==0) FebruaryDays = 29; else FebruaryDays = 28;
provavelmente não devem ser nomeadas constantes, pois a expressão é quase certamente mais legível do queif ((year % YearsBetweenLeapYears)==0) FebruaryDays = FebruaryDaysInLeapYear; else FebruaryDays = FebruaryDaysInNonLeapYear;
. Observe que os mantenedores de padrões indicaram que a duração de fevereiro de 2100 naquele ano não corresponderá à fórmula acima, impedimento de lidar corretamente com essas datas (ou seja, o código não será acionado por excesso de número inteiro ou outros problemas desse tipo).Uma ressalva importante da regra 2 é que, em alguns casos, o código pode depender de números codificados de maneira que não possa ser prontamente representada por uma constante nomeada. Por exemplo, um método que calcula um produto cruzado de dois vetores passados como parâmetros discretos somente terá significado quando usado em vetores tridimensionais. O número necessário de dimensões não é um valor que possa ser alterado significativamente sem reescrever completamente a rotina. Mesmo que se previsse uma possível necessidade de calcular o produto cruzado de três vetores quadridimensionais, o uso de uma constante nomeada para o valor "3" faria pouco para facilitar a satisfação dessa necessidade.
fonte
Como todos os princípios, isso é uma questão de grau. De um modo geral, os literais numéricos no código-fonte são mais suspeitos quanto maiores. Um comprimento máximo como 10 ou um endereço de memória como 0x587FB0 é obviamente uma prática ruim - é quase certo que mais cedo ou mais tarde você precisará repetir esses valores mais de uma vez, criando um risco de incompatibilidade e erros sutis introduzidos em locais que não eram mudou.
0 está no outro extremo da escala; ainda é suspeito, mas não tanto. Você está usando 0 como um valor sentinela? Então você provavelmente deve usar uma constante simbólica, apenas porque a constante pode explicar o que significa. É um acordo cultural extremamente arraigado, como "0 significa conclusão bem-sucedida"? Provavelmente tudo bem. Isso significa "o primeiro item de uma coleção"? Isso pode ser inofensivo, mas se houver um método alternativo, como
first()
eu provavelmente prefiro.fonte
Todo número sem nome que não é imediatamente óbvio no contexto é um número mágico. É um pouco tolo definir números que tenham significado imediatamente óbvio no contexto.
No django (python web framework), posso definir algum campo do banco de dados com um número bruto, como:
que é mais claro (e a prática recomendada ) do que dizer
como é improvável que eu precise alterar o comprimento (e sempre posso comparar com o
max_length
do campo). Se eu precisar alterar o comprimento do campo depois de implantar o aplicativo inicialmente, preciso alterá-lo exatamente em um local por campo no meu código django e depois escrever adicionalmente uma migração para alterar o esquema do banco de dados. Se eu precisar fazer referência amax_length
um campo definido de um tipo de objeto, posso fazê-lo diretamente - se esses campos estavam definindo umaPerson
classe, posso usarPerson._meta.get_field('firstname').max_length
para obter omax_length
sendo usado (definido em um único local). O fato de os mesmos 40 terem sido usados para vários campos é irrelevante, pois posso alterá-los independentemente. O comprimento do nome próprio nunca deve depender do tamanho do nome do meio ou do sobrenome; eles são valores separados e podem mudar independentemente.Frequentemente, os índices de matriz podem usar números sem nome; como se eu tivesse um arquivo CSV de dados que desejo colocar em um dicionário python, com o primeiro elemento na linha como o dicionário que
key
eu escreveria:Claro que eu poderia nomear
index_column = 0
e fazer algo como:ou pior, defina
after_index_col = index_col + 1
se livrar doindex_col+1
, mas isso não torna o código mais claro na minha opinião. Além disso, se eu der oindex_col
nome a, é melhor fazer o código funcionar, mesmo que a coluna não seja 0 (daí arow[:index_col] +
parte).fonte
max_lngth=40
vs.max_length=MAX_LENGTH_NAME
é um exemplo clássico de um número mágico que grita para ser um símbolo. Chegará o dia em que você deseja suportar 45 nomes de caracteres e agora todo uso de "40" é suspeito e deve ser cuidadosamente examinado.40
para1
. Você tem que pensar no contexto.