É sempre uma boa idéia codificar valores em nossos aplicativos?

44

É sempre uma boa ideia codificar valores em nossos aplicativos? Ou é sempre a coisa certa para chamar esses tipos de valores dinamicamente no caso de precisar mudar?

    
por Edward 14.04.2011 / 02:26
fonte

14 respostas

64

Sim, mas torne-o óbvio .

Faça:

Não:

por 14.04.2011 / 02:31
fonte
23

O que eu acho estranho sobre este Q & A até agora é que ninguém realmente tentou definir claramente "código-rígido" ou, mais importante, as alternativas.

tl; dr: Sim, é algumas vezes uma boa idéia para codificar valores, mas não há uma regra simples para quando ; depende completamente do contexto.

A questão restringe-se a valores , o que considero significar números mágicos , mas a resposta para saber se são ou não uma boa ideia é relativa a para as quais são realmente usadas!

Vários exemplos de valores "codificados" são:

  • Valores de configuração

    Eu me encolho sempre que vejo declarações como command.Timeout = 600 . Por que 600? Quem decidiu isso? Foi o tempo limite antes e alguém aumentou o tempo limite como 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 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 dentro dela não é realmente particularmente importante. O volume de uma pirâmide é (1/3) b * h. Nós nos importamos de onde o 1 ou 3 veio? Na verdade não. Um comentarista anterior apontou corretamente que diameter = radius * 2 é provavelmente melhor que diameter = radius * RADIUS_TO_DIAMETER_CONVERSION_FACTOR - mas isso é uma falsa dicotomia.

    O que você deve fazer para este tipo de cenário é criar uma função . Eu não preciso saber como você surgiu com a fórmula, mas eu ainda preciso saber o que é para . Se, em vez de qualquer bobagem escrita acima, eu escrever volume = GetVolumeOfPyramid(base, height) , então tudo fica muito mais claro, e é perfeitamente correto ter números mágicos dentro da função ( return base * height / 3 ) porque é óbvio que eles são apenas parte da fórmula.

    A chave aqui é, obviamente, ter as funções short e simple . Isso não funciona para funções com 10 argumentos e 30 linhas de cálculos. Use composição de função ou constantes nesse caso.

  • Regras de domínio / negócios

    Este é sempre a área cinza porque depende exatamente do valor. Mais da época, 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 título descritivo.

    Estes podem também se tornarem candidatos para abstração de funções, por exemplo, function isLegalDrinkingAge(age) { return age >= 19 } . A única coisa é que muitas vezes sua lógica de negócios é muito mais complicada do que isso, e pode não fazer sentido começar a escrever dezenas de funções com 20 a 30 parâmetros cada. Se não houver uma abstração clara baseada em objetos e / ou funções, então recorrer a constantes é OK.

    A ressalva é que, se você está trabalhando para o departamento de impostos, torna-se realmente muito pesado e honestamente inútil escrever AttachForm(FORM_CODE_FOR_SINGLE_TAXPAYER_FILING_JOINTLY_FOR_DEPRECIATION_ON_ARMPIT_HAIR) . Você não vai fazer isso, você está indo para AttachForm("B-46") porque cada desenvolvedor que já trabalhou ou já vai trabalhar lá vai 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 domínio em si, eles nunca mudam, então eles não são realmente números mágicos.

    Então você tem que 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 é domínio, então você não codifica a menos que haja uma boa chance de que isso mude.

  • Códigos de erro e sinalizadores de status

    Estes são nunca aprovados para codificar, como qualquer pobre coitado que já tenha sido atingido com o Previous action failed due to error code 46 pode lhe dizer. Se o seu idioma oferecer suporte, você deverá usar um tipo de enumeração. Caso contrário, você normalmente terá um arquivo / módulo inteiro cheio de constantes, especificando os valores válidos para um determinado tipo de erro.

    Nunca me deixe ver return 42 em um manipulador de erros, capiche? Sem desculpas.

Eu provavelmente deixei de fora vários cenários, mas acho que isso cobre a maioria deles.

Então, sim, às vezes é uma prática aceitável codificar coisas difíceis. Apenas não seja preguiçoso sobre isso; deve ser uma decisão consciente, em vez de um simples código desleixado.

    
por 14.04.2011 / 20:23
fonte
5

Como complemento a outras respostas. Use constantes para seqüências de caracteres quando possível. Claro, você não quer ter

const string server_var="server_var";

mas você deve ter

const string MySelectQuery="select * from mytable;";

(supondo que você tenha uma consulta onde deseja obter todos os resultados de uma tabela específica, sempre)

Além disso, use constantes para qualquer número diferente de 0 (geralmente). Se você precisar de uma máscara 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, junto com constantes, saiba quando usar enumeradores. O caso acima provavelmente se encaixaria bem em um.

    
por 14.04.2011 / 04:57
fonte
5

Existem vários motivos para atribuir um identificador a um número.

  • Se o número puder ser alterado, ele deverá ter um identificador. É muito mais fácil encontrar NUMBER_OF_PLANETS do que pesquisar todas as instâncias de 9 e considerar se ele deve ser alterado para 8. (Observe que cadeias visíveis ao usuário pode ter que mudar se o software precisar ser usado em um idioma diferente, e isso é uma coisa difícil de prever com antecedência.
  • Se o número for difícil de digitar de alguma forma. Para constantes como pi, é melhor fornecer uma definição de precisão máxima do que redigitá-lo em vários lugares, possivelmente imprecisamente.
  • Se o número ocorre 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 instantaneamente reconhecível. É seguro assumir que todo mundo sabe o que é 3,14159265 .... Não é seguro assumir que todos reconhecerão a constante gravitacional, ou mesmo pi / 2. ("Todos" aqui dependem da natureza do software. Espera-se que os programadores de sistemas conheçam a representação octal de bits de permissão Unix ou similares. Em software de arquitetura naval / marinha, verificando o número de Froude de um casco e velocidade propostos para veja se é 1.1 ou superior pode ser perfeitamente auto-explicativo para qualquer um que deveria estar trabalhando nisso.)
  • Se o contexto não for reconhecível. Todo mundo sabe 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 um valor de taxa .

Isso nos dá critérios para literais de codificação rígida. Eles devem ser imutáveis, não difíceis de digitar, ocorrendo em um único lugar ou contexto, e com significado reconhecível. Não faz sentido definir 0 como ARRAY_BEGINNING, por exemplo, ou 1 como ARRAY_INCREMENT.

    
por 14.04.2011 / 16:10
fonte
4

Is it ever a good idea to hardcode values into our applications?

Eu codifico valores somente se os valores forem especificados na Especificação (em uma versão final da especificação), por exemplo A resposta HTTP OK será sempre 200 (a menos que seja alterada no RFC), portanto, 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.

O motivo pelo qual especifiquei especificações é que a alteração de constantes nas especificações requer um gerenciamento de mudanças, no qual as partes interessadas revisarão a alteração e aprovarão / desaprovarão. Isso nunca acontece durante a noite e leva meses / anos para uma aprovação. Não se esqueça de que muitos desenvolvedores usam especificações (por exemplo, HTTP), por isso mudar significa quebrar milhões de sistemas.

    
por 14.04.2011 / 15:27
fonte
3
  • se o valor puder mudar e, de fato, puder mudar, então codifique-o sempre que possível, contanto que o esforço envolvido não exceda o retorno esperado
  • alguns valores não podem ser codificados em código; siga as orientações de Jonathan nesses casos (raros)
por 14.04.2011 / 04:28
fonte
3

Depende do que você considera hardcoding. Se você tentar evitar todas as coisas codificadas, você acaba no território da codificação e cria um sistema que somente o criador pode gerenciar (e esse é o código definitivo)

Muitas coisas são codificadas em qualquer estrutura razoável e funcionam. ou seja, não há nenhuma razão técnica pela qual eu não deveria ser capaz de alterar o ponto de entrada de um aplicativo C # (static void Main), mas codificar isso não cria problemas para nenhum usuário (exceto o ocasional SO question )

A regra geral que uso é que tudo o 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 estão mudando (pi, constante gravitacional, uma constante em uma fórmula matemática - pense no volume de uma esfera).

Também é bobagem não codificar coisas ou processos que terão um impacto em seu sistema que exigirá programação em qualquer instância, ou seja, é um desperdício permitir que o usuário adicione campos dinâmicos a um formulário, se qualquer campo adicionado exigir o desenvolvedor de manutenção para entrar e escrever algum script que fará com que a coisa 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, mas apenas os desenvolvedores no departamento de TI podem usá-lo, e é apenas um pouco mais fácil de usá-lo do que para fazer isso no Visual Studio.

Assim, a linha de fundo, se uma coisa deve ser codificada, é uma função de duas variáveis:

  • o valor será alterado
  • como uma alteração no valor afetará o sistema
por 14.04.2011 / 09:21
fonte
2

Eu codifiquei recentemente uma função MySQL para calcular corretamente a distância entre dois pares de latitude / longitude. Você não pode simplesmente fazer pythagorus; linhas de longitude se aproximam à medida que a latitude aumenta em direção aos pólos, então há alguns trigonos meio cabeludos envolvidos. O ponto é que eu estava bastante dividido sobre o código rígido do valor que representa o raio da Terra em milhas.

Eu acabei fazendo isso, embora o fato seja que as linhas lat / lng estão muito mais próximas umas das outras, digamos, a lua. E minha função iria diminuir drasticamente as distâncias entre os pontos em Júpiter. Eu percebi que as chances de o site que estou construindo ter um local extraterrestre sendo acessado são muito pequenas.

    
por 14.04.2011 / 14:27
fonte
1

Tenho notado que sempre que você pode extrair dados de seu código, isso melhora o que resta. Você começa a perceber novas refatorações e a melhorar seções inteiras do seu código.

É uma boa ideia trabalhar para extrair constantes, não considerá-la uma regra estúpida, pense nisso como uma oportunidade de 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-os em arrays me ajudou a reduzir alguns arquivos em 90% de seu tamanho e a corrigir alguns copy & cole bugs nesse meio tempo.

Ainda não vejo uma vantagem em não extrair dados.

    
por 14.04.2011 / 08:13
fonte
1

Bem, isso depende do seu idioma ser compilado. Se não for compilado, não é grande coisa, basta editar o código-fonte, mesmo que seja um pouco delicado para um não programador.

Se você estiver programando com uma linguagem compilada, isso claramente não é uma boa idéia, porque se as variáveis mudarem, você terá que recompilar, o que é um grande desperdício 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.

    
por 14.04.2011 / 14:06
fonte
1

Duas ocasiões em que as constantes são (na minha opinião, pelo menos) OK:

  1. Constantes que se relacionam com nada mais; você pode alterar essas constantes sempre que desejar, sem precisar alterar mais nada. Exemplo: a largura padrão de uma coluna de grade.

  2. Constantes absolutamente imutáveis, precisas e óbvias, como "número de dias por semana". days = weeks * 7 Substituir 7 por uma constante DAYS_PER_WEEK dificilmente fornece qualquer valor.

por 14.04.2011 / 14:26
fonte
0

Eu concordo completamente com o Jonathan, mas como todas as regras existem exceções ...

"Número mágico na especificação: número mágico no código"

Basicamente, afirma que qualquer número mágico que permaneça na especificação após tentativas razoáveis de obter contexto descritivo para eles deve ser refletido como tal no código. Se 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.

Eu realizei alguns contratos de interface nos quais é necessário preencher mensagens com valores mapeados no banco de dados. Na maioria dos casos, o mapeamento é bastante direto e se encaixaria nas linhas de orientação 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 tinham que ser transmitidos na estrutura eram constantes impostas pela especificação do sistema distante. isso combinado 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 uma razão, apenas disseram "coloque M aqui" ou "coloque 4.10.53.10100.889450.4452 aqui". Eu não tentei colocar um comentário ao lado de todos eles teria tornado o código resultante ilegível. No entanto, certifiquei-me de que as seções de código em que esses valores mágicos aparecem estivessem adequadamente isoladas e que seus contêineres (classes, pacotes) fossem nomeados apropriadamente para apontar diretamente para a especificação que os aplicava.

Dito isto, quando você pensa sobre isso ... é praticamente tudo sobre torná-lo <óbvio ...

    
por 14.04.2011 / 07:40
fonte
0

Se você está codificando o valor da constante gravitacional da Terra, ninguém vai se importar. Se você codificar o endereço IP do seu servidor proxy, você está com problemas.

    
por 14.04.2011 / 09:02
fonte
0

Principalmente não, mas acho que vale a pena notar que você terá mais problemas quando começar a duplicar o valor codificado. Se você não duplicar (ex. Usá-lo apenas uma vez na implementação de uma classe), então não usar uma constante pode ser bom.

    
por 14.04.2011 / 09:23
fonte