É sempre uma boa ideia codificar valores permanentemente em nossos aplicativos? Ou é sempre a coisa certa chamar esses tipos de valores dinamicamente, caso eles precisem ser alterados?
Comentários
Resposta
Sim, mas torne-a óbvia .
Faça:
- use constantes
- use um descritivo nome da variável
Não:
- tenha nenhum número mágico flutuando no código
Comentários
- O que é mais limpo,
diameter = 2 * radius
oudiameter = RADIUS_TO_DIAMETER_FACTOR * radius
? De fato, há casos em que um número mágico pode ser a melhor solução. - Não posso ‘ concordar com Essa resposta é suficiente. Eu tendo a pensar em programação como um romancista. Você conta sua história por meio do código e, se as pessoas não entenderem a lógica, isso torna seu código inútil, na minha opinião. Isso ‘ s por que convenções de nomenclatura bem elaboradas são essencialmente legíveis. Além disso, não há uma boa razão para usar números mágicos. Ao usar números mágicos, você remove o ” por que ” da equação e torna mais difícil compreendê-la tand. Por exemplo: ” diameter = 2 * radius ” Para que servem os dois? Este ” diâmetro = RADIUS_TO_DIAMETER_FACTOR * raio ” faz muito mais sentido.
- diâmetro = 2 * raio é direto de matemática do ensino médio. A razão para não nomear o ” 2 ” é que para ter o valor de qualquer outra coisa exigiria uma mudança nas leis de física ou matemática, ou ambos. (Por outro lado, nomear Pi ou constante de Plancks é uma boa opção para facilitar a leitura).
- @Joonas: Pfft. Certamente você quer dizer
diameter = radius << 1
? Suponho que também poderia serdiameter = radius << RADIUS_TO_DIAMETER_BITS_TO_SHIFT
. - que ‘ sobre alguns
diameter = radius.toDiameter()
Resposta
O que acho estranho nesta Q & Até agora, ninguém tentou definir claramente “hard-code” ou, mais importante, as alternativas.
tl; dr : Sim, às vezes é uma boa ideia embutir valores em código, mas não existe uma regra simples quanto a quando ; depende totalmente do contexto.
A questão se limita a valores , que considero significando números mágicos , mas a resposta para se eles são ou não uma boa ideia é em relação ao para que eles são realmente usados!
Vários exemplos de “codificados permanentemente “os valores são:
-
Valores de configuração
Eu me encolho sempre que vejo declarações como
command.Timeout = 600
. Por que 600? Quem decidiu isso? O tempo limite expirou antes e alguém o considerou um hack em vez de corrigir o problema de desempenho subjacente? Ou é realmente alguma expectativa conhecida e documentada para o tempo de processamento?Estes não devem ser números mágicos ou constantes, eles devem ser externalizados em um arquivo de configuração ou banco de dados em algum lugar com um nome significativo, porque seu valor ideal é determinado em grande parte ou inteiramente pelo ambiente em que o aplicativo está sendo executado.
-
Fórmulas matemáticas
As fórmulas geralmente tendem a ser bastante estáticas, de modo que a natureza dos valores constantes internos não é particularmente importante. O volume de uma pirâmide é (1/3) b * h. Nós nos importamos de onde veio o 1 ou 3? Na verdade. Um comentarista anterior apontou corretamente que
diameter = radius * 2
é provavelmente melhor do quediameter = radius * RADIUS_TO_DIAMETER_CONVERSION_FACTOR
– mas essa é uma falsa dicotomia.O que você deve fazer para esse tipo de cenário é criar uma função . Não preciso saber como você surgiu com a fórmula, mas ainda preciso saber para que serve . Se, em vez de qualquer uma das bobagens escritas acima, eu escrever
volume = GetVolumeOfPyramid(base, height)
, de repente tudo se torna muito mais claro, e é perfeitamente normal ter números mágicos dentro de a função (return base * height / 3
) porque é óbvio que são apenas parte da fórmula.A chave aqui é, obviamente, ter funções curtas e simples . Isso não funciona para funções com 10 argumentos e 30 linhas de cálculo. Use composição de função ou constantes nesse caso.
-
Domínio / regras de negócios
Este é sempre a área cinza porque depende de qual é exatamente o valor. Na maior parte do tempo, são esses números mágicos específicos que são candidatos a se tornarem constantes, porque isso torna o programa mais fácil de entender sem complicar a lógica do programa. Considere o teste
if Age < 19
vs.if Age < LegalDrinkingAge
; você provavelmente pode descobrir o que está acontecendo sem a constante, mas é mais fácil com o descritivo título.Eles podem também se tornar candidatos para abstração de função, por exemplo
function isLegalDrinkingAge(age) { return age >= 19 }
. A única coisa é que muitas vezes sua lógica de negócios é muito mais complicado do que isso, e pode não fazer sentido começar a escrever dezenas de funções com 20-30 parâmetros cada. Se não houver uma abstração clara baseada em objetos e / ou funções, então o recurso a constantes está OK.A ressalva é que, se você está trabalhando para o departamento de impostos, torna-se realmente realmente oneroso e honestamente inútil escrever
AttachForm(FORM_CODE_FOR_SINGLE_TAXPAYER_FILING_JOINTLY_FOR_DEPRECIATION_ON_ARMPIT_HAIR)
. Você não vai fazer isso t, você vaiAttachForm("B-46")
porque cada desenvolvedor que já trabalhou ou trabalhará lá saberá que “B-46” é o código de formulário para um único contribuinte arquivando blá blá blá – os códigos de formulário são parte do próprio domínio, eles nunca mudam, portanto, não são números realmente mágicos.Portanto, você precisa usar constantes com moderação na lógica de negócios; basicamente você tem que entender se esse “número mágico” é na verdade um número mágico ou se é um aspecto bem conhecido do domínio. Se for um domínio, você não deve programá-lo a menos que haja um há uma boa chance de que mude.
-
Códigos de erro e sinalizadores de status
Estes nunca são adequados para hard-code, como qualquer pobre coitado que já foi atingido com
Previous action failed due to error code 46
pode lhe dizer. Se o seu idioma for compatível, você deve usar um tipo de enumeração. Caso contrário, você geralmente terá um arquivo / módulo inteiro cheio de constantes especificando os valores válidos para um tipo de erro específico.Nunca me deixe ver
return 42
em um manipulador de erros, capiche? Sem desculpas.
Provavelmente deixei de fora vários cenários, mas acho que abrangem a maioria deles.
Então, sim, às vezes é uma prática aceitável para coisas de código rígido. Apenas não seja preguiçoso sobre isso; deve ser uma decisão consciente em vez de um código desleixado e simples.
Comentários
- Obrigado pelo bom detalhamento! – a maioria das pessoas não ‘ t pensa em todas as opções que eu adicionaria ” Configuração do ambiente ” – Acho que isso deve ser evitado (não embutido em código), já que a maioria dos dados deve ser colocada em um arquivo de configuração ou banco de dados. Isso segue o princípio de ” manter os dados e a lógica separados ” que é o esteio do MVC ou MVVM. string TestServerVar = ” foo “; string ProdServerVal = ” bar “;
Resposta
Existem vários motivos para atribuir um identificador a um número.
- Se o número puder mudar, deve ter um identificador. É muito mais fácil encontrar NUMBER_OF_PLANETS do que pesquisar todas as instâncias de 9 e considerar se deve ser alterado para 8. (Observe que visível para o usuário strings podem ter que mudar se o software tiver que ser usado em um idioma diferente, e isso “é uma coisa difícil de prever com antecedência.)
- Se o número é difícil de digitar de qualquer forma. Para constantes como pi, é melhor fornecer uma definição de precisão máxima do que redigitá-la em vários lugares, possivelmente de forma imprecisa.
- Se o número ocorrer em lugares diferentes. Você não deveria “ter que olhar para dois usos de 45 em funções adjacentes e se perguntar se eles significam a mesma coisa.
- Se o significado não for imediatamente reconhecível. É seguro presumir que todos sabem o que é 3.14159265 …. Não é seguro presumir que todos reconhecerão a constante gravitacional, ou mesmo pi / 2. (“Todo mundo” aqui depende da natureza do software. Os programadores de sistema devem saber a representação octal de bits de permissão Unix ou semelhantes. No software de arquitetura naval / marinha, verificar o número de Froude de um casco proposto e a velocidade para veja se é 1.1 ou superior pode ser perfeitamente autoexplicativo para quem deveria estar trabalhando nisso.)
- Se o contexto não for reconhecível . Todos sabem que há 60 minutos em uma hora, mas multiplicar ou dividir por 60 pode não ser claro se não houver indicações imediatas de que a quantidade é um valor de tempo ou de taxa .
Isso nos fornece critérios para literais de codificação permanente. Eles devem ser imutáveis, não difíceis de digitar, ocorrendo em um lugar ou contexto apenas e com significado reconhecível. Não há nenhum ponto em definir 0 como ARRAY_BEGINNING, por exemplo, ou 1 como ARRAY_INCREMENT.
Resposta
Como um complemento a outras respostas. Use constantes para strings quando possível. Obviamente, você não quer
const string server_var="server_var";
, mas deveria ter
const string MySelectQuery="select * from mytable;";
(assumindo que você realmente tem uma consulta na qual deseja obter todos os resultados de uma tabela específica, sempre)
Fora isso, use constantes para qualquer número diferente de 0 (normalmente). Se você precisar uma máscara de bits de permissão de 255, não use
const int 8th_bit=255; //or some other obscure naming scheme that equates to 255.
em vez disso, use
const int AllowGlobalRead=255;
É claro que, junto com as constantes, saiba quando usar enumeradores. O caso acima provavelmente se encaixaria bem em um.
Comentários
- typedef enum {state_0 = 0, state_1 = 1, state_2 = 2, .. .} … Não ‘ ria, eu ‘ já vi isso acontecer. Bata na cabeça daquela pessoa com um peixe molhado!
- @ Rapidamente bem, é claro que você ‘ quer algo mais parecido com
typedef enum {init_state=0, parse_state=1, evaluation_state=2, ... }
- THIS_NAMING_CONVENTION_IS_RECOMMENDED_FOR_CONSTANTS
- Para strings, você não ‘ quer apenas constantes. Você deseja colocar quaisquer strings visíveis ao usuário em algum tipo de arquivo de recurso (os detalhes dependerão da sua plataforma) para que possa mudar para outro idioma facilmente.
- Você também pode querer manter a lógica de negócios strings (como consultas SQL) em um arquivo de recurso com algum tipo de criptografia ou ofuscação. Isso impedirá ” curiosos ” usuários de fazer engenharia reversa de sua lógica (ou esquema de banco de dados).
Resposta
Depende do que você considera codificar. Se você tentar evitar todo e qualquer conteúdo codificado, acabará no território de softcoding e criará um sistema que apenas o criador pode gerenciar (e esse é o ultimate hardcode)
Muitas coisas são codificadas em qualquer estrutura razoável e funcionam. ou seja, não há nenhuma razão técnica para que eu não seja capaz de alterar o ponto de entrada de um aplicativo C # (estático void Main ), mas uma codificação que não cria problemas para nenhum usuário (exceto a questão de SO ocasional)
A regra que eu uso é que qualquer coisa que pode e vai mudar, sem afetar o estado de todo o sistema, deve ser confugurável.
Então, IMHO, é bobagem não codificar coisas que nunca mudam (pi, constante gravitacional, uma constante em uma fórmula matemática – pense no volume de uma esfera).
Além disso, é tolice não codificar coisas ou processos que terão um impacto em seu sistema que exigirá programação em qualquer instância, i .e. é um desperdício permitir que o usuário adicione campos dinâmicos a um formulário, se qualquer campo adicionado exigir que o desenvolvedor de manutenção vá e escreva algum script que fará com que isso funcione. Também é estúpido (e eu já vi isso algumas vezes em ambientes corporativos) criar alguma ferramenta de configuração, então nada é codificado, ainda, apenas os desenvolvedores no departamento de TI podem usá-lo, e é apenas um pouco mais fácil usá-lo do que no Visual Studio.
Portanto, no final das contas, se algo deve ser codificado é uma função de duas variáveis:
- o valor mudará
- como uma mudança no valor afetará o sistema
Resposta
É sempre uma boa ideia codificar os valores em nossos aplicativos?
Eu fixo os valores no código apenas se os valores são especificados na Especificação (em uma versão final da especificação), por exemplo A resposta HTTP OK sempre será 200
(a menos que mude no RFC), então, você verá (em alguns dos meus códigos) constantes como:
public static final int HTTP_OK = 200;
Caso contrário, eu armazeno constantes no arquivo de propriedades.
A razão pela qual eu especifiquei as especificações, é que alterar constantes nas especificações requer gerenciamento de mudanças, no qual, as partes interessadas irão revisar a mudança e aprovar / desaprovar. Isso nunca acontece durante a noite e leva meses / anos para ser aprovado. Não se esqueça de que muitos desenvolvedores usam especificações (por exemplo, HTTP), portanto, alterá-las significa quebrar milhões de sistemas.
Resposta
- se o valor pode mudar, e de fato pode mudar, então soft-code-o sempre que possível, desde que o esforço envolvido não exceda o retorno esperado
- alguns valores não podem ser soft-coded; siga as diretrizes de Jonathan nesses (raros) casos
Resposta
Eu percebi que sempre que você pode extrair dados de seu código, melhora o que resta. Você começa a notar novas refatorações e a melhorar seções inteiras de seu código.
É apenas uma boa ideia trabalhar para extrair constantes, não considere isso uma regra estúpida, pense nisso como uma oportunidade para codificar melhor.
A maior vantagem seria a maneira como você pode encontrar constantes semelhantes sendo a única diferença em grupos de código – abstraindo-as em matrizes me ajudou a reduzir alguns arquivos em 90% de seu tamanho e corrigir bastante enquanto isso, copie & e cole bugs.
Ainda não vi uma única vantagem em não extrair dados.
Resposta
Recentemente codifiquei uma função MySQL para calcular corretamente a distância entre dois pares de latitude / longitude. Você não pode simplesmente fazer o pythagorus; as linhas de longitude ficam mais próximas à medida que a latitude aumenta em direção aos pólos, então há um pouco de trigonometria cabeluda envolvida. O ponto é, eu estava muito indeciso sobre se deveria codificar o valor que representa o raio da Terra em milhas.
Acabei fazendo isso, embora o fato seja que as linhas lat / lng são muito mais próximas, digamos, na lua. E minha função subestima drasticamente as distâncias entre os pontos de Júpiter. Achei que as chances de o site que estou construindo ter um local extraterrestre inserido é muito reduzido.
Comentários
- Sim, provavelmente, mas o quê sobre google.com/moon
Resposta
Bem, depende se a sua linguagem foi compilada. Se não for compilada, não é grande coisa, você apenas edita o código-fonte, mesmo que seja um pouco delicado para um não programador.
Se você está programando com uma linguagem compilada, isso claramente não é uma boa ideia, porque se as variáveis mudarem, você terá que recompilar, o que é uma grande perda de tempo se você quiser ajustar essa variável.
Você não precisa fazer algum controle deslizante ou interface para alterar dinamicamente sua variável, mas o mínimo que você pode fazer é um arquivo de texto.
Por exemplo, com meu projeto ogre, estou sempre usando a classe ConfigFile para carregar uma variável que escrevi em um arquivo de configuração.
Resposta
Duas ocasiões em que as constantes são (pelo menos na minha opinião) OK:
-
Constantes que não se relacionam com mais nada; você pode alterar essas constantes sempre que desejar, sem precisar alterar nada mais. Exemplo: a largura padrão de uma coluna de grade.
-
Absolutamente imutáveis, precisas, constantes óbvias, como “número de dias por semana”.
days = weeks * 7
Substituir7
por uma constanteDAYS_PER_WEEK
dificilmente fornece qualquer valor.
Resposta
Eu concordo totalmente com Jonathan, mas como todas as regras, há exceções …
“Número mágico na especificação: número mágico no código”
Basicamente, afirma que quaisquer números mágicos que permanecerem na especificação após tentativas razoáveis de obter um contexto descritivo para eles devem ser refletidos como tal no código. Se os números mágicos permanecerem no código, todos os esforços devem ser feitos para isolá-los e torná-los claramente vinculados ao seu ponto de origem.
Realizei alguns contratos de interface onde é necessário preencher as mensagens com os valores mapeados do banco de dados. Na maioria dos casos, o mapeamento é bastante direto e se encaixaria nas diretrizes gerais de Jonathan, mas eu encontrei casos em que a estrutura da mensagem de destino era simplesmente horrível.Mais de 80% dos valores que deveriam ser repassados na estrutura eram constantes impostas pela especificação do sistema distante. isso, juntamente com o fato de que a estrutura da mensagem era gigantesca, fez com que MUITAS dessas constantes tivessem que ser preenchidas. Na maioria dos casos, eles não forneceram um significado ou motivo, apenas disseram “coloque M aqui” ou “coloque 4.10.53.10100.889450.4452 aqui”. Eu também não tentei colocar um comentário próximo a todos eles, isso tornaria o código resultante ilegível. No entanto, certifiquei-me de que as seções de código onde esses valores mágicos aparecem estão devidamente isoladas e que seus contêineres (classes, pacotes) nomeados apropriadamente para apontar diretamente para a especificação que os impõe.
Dito isso, quando você pensa sobre isso … trata-se basicamente de torná-lo óbvio …
Resposta
Se você está codificando o valor da constante gravitacional da Terra, ninguém vai se importar. Se você codificar o endereço IP de seu servidor proxy, terá problemas.
Comentários
- Você pode precisar de mais precisão para earth ‘ s constante gravitacional, portanto, codificá-la várias vezes pode levar a problemas.
- Peter Noone? De Herman ‘ s Eremitas ?
- A aceleração gravitacional na Terra é quase 9,81 m / s ^ 2 para a maioria das latitudes e altitudes (claro, se você ‘ estiver procurando por petróleo subterrâneo, ou disparando ICBMs sobre o Pólo Norte, sabendo que a variação da gravidade é muito importante para muito mais casas decimais), com a aceleração gravitacional em outros planetas sendo um número diferente, mas até onde eu sei, a constante gravitacional é constante em todo o universo. Muitas coisas físicas teriam que mudar se g fosse variável.
Resposta
Principalmente não, mas acho que vale a pena notar que você Terei mais problemas quando começar a duplicar o valor embutido no código. Se você não o duplicar (por exemplo, usá-lo apenas uma vez na implementação de uma classe), então não usar uma constante pode ser bom.
pi
pode mudar …