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


45

É sempre uma boa idéia codificar valores em nossos aplicativos? Ou é sempre a coisa certa chamar esses tipos de valores dinamicamente, caso eles precisem mudar?


2
um parâmetro de configuração iria ajudá-lo
Gopi

54
Você nunca sabe quando o valor de pimudança de poder ...
Gabe

12
Cara, acho que pessoas como @gabe são a razão de ser uma "regra". Se você repetir 3,14 em 20 lugares no seu código e descobrir que realmente precisa de mais precisão, estará ferrado. Não sabia que isso não era óbvio.
Bill K

17
Isso foi um pouco rude, @Bill. O @Gabe estava claramente brincando, mas fora isso, a questão era sobre codificação codificada versus parâmetros de configuração, não usar números mágicos constantes e repetidos em vários lugares.
David Conrad

1
Sim, às vezes pode ser uma boa ideia codificar. Veja o artigo da Wikipedia sobre o antipadrão "Softcoding".
usar o seguinte comando

Respostas:


64

Sim, mas deixe óbvio .

Faz:

  • use constantes
  • use um nome de variável descritivo

Não faça:


44
Qual é mais limpo diameter = 2 * radiusou diameter = RADIUS_TO_DIAMETER_FACTOR * radius? De fato, existem casos em que um número mágico pode ser uma solução melhor.
Joonas Pulakka

5
Não posso concordar com esta resposta o suficiente. Costumo pensar em programação como ser um romancista. Você conta sua história através do código e, se as pessoas não conseguem entender a lógica, isso torna seu código inútil na minha opinião. É por isso que as convenções de nomenclatura bem pensadas são essencialmente para facilitar a leitura. Além disso, não há boas razões para usar números mágicos. Usando números mágicos, você remove o "porquê" da equação e torna mais difícil de entender. Por exemplo: "diâmetro = 2 * raio" Para que servem os dois? Este "diâmetro = RADIUS_TO_DIAMETER_FACTOR * raio" faz muito mais sentido.
amigos estão dizendo sobre chrisw

9
diâmetro = 2 * raio é direto da matemática do ensino médio. A razão para não nomear o "2" é que, para que ele tenha o valor de qualquer outra coisa, seria necessário alterar as leis da física ou da matemática, ou ambas. (Por outro lado, nomear Pi ou Plancks constante é uma boa jogada para facilitar a leitura).
quickly_now

8
@Joonas: Pfft. Certamente você quer dizer diameter = radius << 1? Suponho que também poderia ser diameter = radius << RADIUS_TO_DIAMETER_BITS_TO_SHIFT.
Ant

4
Que tal algunsdiameter = radius.toDiameter()
Carson Myers

27

O que acho estranho nessas perguntas e respostas até agora é que ninguém tentou definir claramente "código fixo" ou, mais importante, as alternativas.

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

A pergunta restringe-se a valores , que eu entendo como números mágicos , mas a resposta para saber se eles são ou não uma boa ideia é relativa ao que eles realmente são usados!

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

  • Valores de configuração

    Eu me arrepio sempre que vejo declarações como essa 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, 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 bem estáticas, de modo que a natureza dos valores constantes no interior não é realmente particularmente importante. O volume de uma pirâmide é (1/3) b * h. Nos importamos com a origem do 1 ou 3? Na verdade não. Um comentarista anterior apontou, com razão, que diameter = radius * 2provavelmente é melhor do que diameter = radius * RADIUS_TO_DIAMETER_CONVERSION_FACTOR- mas isso é uma dicotomia falsa.

    O que você deve fazer para esse tipo de cenário é criar uma função . Não preciso saber como você criou a fórmula, mas ainda preciso saber para que serve . Se, em vez de qualquer bobagem escrita acima, eu escrever volume = GetVolumeOfPyramid(base, height), de repente tudo se torna muito mais claro, e é perfeitamente bom 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 funções curtas e simples . Isso não funciona para funções com 10 argumentos e 30 linhas de cálculos. Use composição ou constantes de funções nesse caso.

  • Regras de domínio / negócios

    Esta é sempre a área cinzenta porque depende de qual é exatamente o valor. Na maioria das vezes, são esses números mágicos específicos que são candidatos à transformação em constantes, porque isso facilita a compreensão do programa sem complicar a lógica do programa. Considere o teste if Age < 19vs if Age < LegalDrinkingAge; você provavelmente pode descobrir o que está acontecendo sem a constante, mas é mais fácil com o título descritivo.

    Eles também podem se tornar candidatos à abstração de funções, por exemplo function isLegalDrinkingAge(age) { return age >= 19 }. A única coisa é que geralmente a 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 com base em objetos e / ou funções, recorrer a constantes é aceitável.

    A ressalva é que, se você trabalha para o departamento tributário, torna-se muito, muito 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, AttachForm("B-46")porque todo desenvolvedor que já trabalhou ou que irá trabalhar lá saberá que "B-46" é o código do formulário para um único contribuinte que arquiva blá blá blá - os códigos de formulário fazem parte do próprio domínio, nunca mudam; portanto, não são realmente números mágicos.

    Então você precisa usar constantes com moderação na lógica de negócios; basicamente, você precisa entender se esse "número mágico" é realmente um número mágico ou se é um aspecto bem conhecido do domínio. Se for domínio, você não o codifica, a menos que haja uma chance muito boa de que isso mude.

  • Códigos de erro e sinalizadores de status

    Isso nunca é bom para codificar, como qualquer pobre bastardo que já foi atingido com o Previous action failed due to error code 46pode dizer. Se o seu idioma suportar, você deve 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 tipo de erro específico.

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

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. Só não seja preguiçoso; deve ser uma decisão consciente, e não um código antigo e desleixado.


Obrigado pela boa repartição! - a maioria das pessoas não pensa em todas as opções que eu adicionaria "Configuração do ambiente" - acho que elas devem ser evitadas (não codificadas), pois a maioria dos dados deve ser colocada em um arquivo de configuração ou banco de dados. Isso segue o princípio de "manter dados e lógica separados", que é a base do MVC ou MVVM. string TestServerVar = "foo"; string ProdServerVal = "bar";
m1m1k

7

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

  • Se o número puder mudar, ele deve ter um identificador. É muito mais fácil encontrar NUMBER_OF_PLANETS do que procurar todas as instâncias 9 e considerar se ela deve ser alterada para 8. (Observe que cadeias visíveis ao usuário podem precisar ser alteradas 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 digitá-la novamente em vários lugares, possivelmente imprecisa.
  • Se o número ocorrer em lugares diferentes. Você não precisa examinar 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. ("Todo mundo" aqui depende da natureza do software. É esperado que os programadores de sistemas conheçam a representação octal dos bits de permissão do Unix ou similares. No software de arquitetura naval / marinha, verificando o número de Froude de um casco proposto e a velocidade para ver se é 1.1 ou superior pode ser perfeitamente auto-explicativo para quem deveria estar trabalhando nele.)
  • Se o contexto não for reconhecível. Todo mundo sabe que existem 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 seja um valor de tempo ou de taxa.

Isso nos fornece critérios para literais codificados. Eles devem ser imutáveis, não difíceis de digitar, ocorrendo apenas em um local ou contexto e com significado reconhecível. Não faz sentido definir 0 como ARRAY_BEGINNING, por exemplo, ou 1 como ARRAY_INCREMENT.


5

Como um complemento para 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ê deveria ter

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

(supondo que você realmente tenha 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 (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;

Obviamente, junto com as constantes, sabem quando usar enumeradores. O caso acima provavelmente se encaixaria bem em um.


typedef enum {state_0 = 0, state_1 = 1, state_2 = 2, ...} ... Não ria, eu já vi isso. Bata nessa pessoa com um peixe molhado na cabeça!
quickly_now

@quickly bem é claro que você iria querer algo mais parecidotypedef enum {init_state=0, parse_state=1, evaluation_state=2, ... }
Earlz

6
THIS_NAMING_CONVENTION_IS_RECOMMENDED_FOR_CONSTANTS
StuperUser

4
Para strings, você não quer apenas constantes. Você deseja inserir qualquer string visível ao usuário em algum tipo de arquivo de recurso (os detalhes dependerão da sua plataforma) para poder mudar para outro idioma facilmente.
David Thornley

Você também pode colar cadeias relacionadas à lógica de negócios (como consultas SQL) em um arquivo de recurso com algum tipo de criptografia ou ofuscação. Isso impedirá que usuários "curiosos" façam engenharia reversa de sua lógica (ou esquema do banco de dados).
TMN

4

Depende do que você considera codificado. Se você tentar evitar toda e qualquer coisa codificada, você acaba no território da codificação eletrônica e cria um sistema que apenas 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 para não poder alterar o ponto de entrada de um aplicativo C # (static void Main), mas codificar permanentemente que não cria problemas para nenhum usuário (exceto a pergunta SO ocasional )

A regra de ouro que uso é que tudo o que pode e vai mudar, sem afetar o estado de todo o sistema, deve ser desconfigurá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).

Também é tolice não codificar coisas ou processos que terão um impacto em seu sistema que exigirão programação em qualquer instância, ou seja, é desperdício permitir ao usuário adicionar campos dinâmicos a um formulário, se algum campo adicionado exigir que o desenvolvedor de manutenção entre e escreva um script que faça essa coisa funcionar. Além disso, é estúpido (e já vi isso algumas vezes em ambientes corporativos) criar alguma ferramenta de configuração, para que nada seja codificado, mas apenas os desenvolvedores do departamento de TI podem usá-lo, e é um pouco mais fácil de usá-lo do que para fazer isso no Visual Studio.

Portanto, a questão de saber se uma coisa deve ser codificada é uma função de duas variáveis:

  • o valor mudará
  • como uma alteração no valor afetará o sistema

4

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

Eu codifico os valores apenas se os valores estiverem 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 na RFC); assim, você verá (em alguns dos meus códigos ) constantes como:

public static final int HTTP_OK = 200;

Caso contrário, armazeno constantes no arquivo de propriedades.

A razão pela qual especifiquei as especificações é que a alteração de constantes nas especificações requer gerenciamento de alterações, no qual os interessados ​​revisam a alteração e aprovam / desaprovam. Isso nunca acontece da noite para o dia e leva meses / anos para uma aprovação. Não esqueça que muitos desenvolvedores usam especificações (por exemplo, HTTP), portanto, mudar isso significa quebrar milhões de sistemas.


3
  • se o valor puder mudar, e realmente puder mudar, codifique-o sempre que possível, desde que o esforço envolvido não exceda o retorno esperado
  • alguns valores não podem ser codificados por software; siga as diretrizes de Jonathan nesses casos (raros)

3

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

É apenas uma boa idéia trabalhar para extrair constantes, não a considere uma regra estúpida, pense nela 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-as em matrizes me ajudou a reduzir alguns arquivos em 90% do seu tamanho e a corrigir alguns erros de copiar e colar enquanto isso. .

Ainda não vi uma única vantagem em não extrair dados.


2

Eu recentemente codifiquei uma função MySQL para calcular corretamente a distância entre dois pares de lat / long. Você não pode simplesmente fazer pitágoras; as linhas de longitude se aproximam à medida que a latitude aumenta em direção aos polos, então há alguns gatinhos meio peludos envolvidos. A questão é que fiquei bastante impressionado com a possibilidade de codificar o valor que representa o raio da Terra em quilômetros.

Acabei fazendo isso, mesmo que o fato seja que as linhas de latitude / longitude estejam muito mais próximas, digamos, da lua. E minha função subnotificaria drasticamente as distâncias entre pontos em Júpiter. Imaginei que as chances do site que estou construindo com uma localização extraterrestre ser muito pequena.


Sim, provavelmente, mas e o google.com/moon
Residuum

1

Bem, depende se o seu idioma é 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ê está programando com uma linguagem compilada, isso claramente não é uma boa ideia, porque se as variáveis ​​mudarem, é necessário recompilar, o que é uma grande perda de tempo, se você deseja ajustar essa variável.

Você não precisa criar um controle deslizante ou interface para alterar dinamicamente a variável dele, mas o mínimo que você pode fazer é um arquivo de texto.

Por exemplo, no meu projeto ogre, estou sempre usando a classe ConfigFile para carregar uma variável que escrevi em um arquivo de configuração.


1

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

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

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


0

Eu concordo completamente 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 qualquer número mágico que permaneça na especificação após tentativas razoáveis ​​de obter um contexto descritivo para eles deve ser refletido 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 nos quais é necessário preencher mensagens com valores mapeados no banco de dados. Na maioria dos casos, o mapeamento é bastante direto e caberia nas linhas gerais de Jonathan, mas encontrei casos em que a estrutura da mensagem de destino era simplesmente horrível. Mais de 80% dos valores que precisavam ser transmitidos na estrutura eram constantes impostas pela especificação do sistema distante. isso associado ao fato de que a estrutura da mensagem era gigantesca fazia com que muitas dessas constantes tivessem que ser preenchidas. Na maioria dos casos, eles não forneceram significado ou razão, apenas disseram "coloque M aqui" ou "coloque 4.10.53.10100.889450.4452 aqui". Não tentei colocar um comentário ao lado de todos eles, pois isso tornaria o código resultante ilegível.

Dito isto, quando você pensa sobre isso ... é praticamente tudo sobre tornar isso óbvio ...


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, terá problemas.


1
Você pode precisar de mais precisão para a constante gravitacional da Terra, então codificá-la várias vezes pode levar a problemas.
usar o seguinte comando

1
Peter Noone? Dos eremitas de Herman?
David Conrad

A aceleração gravitacional na Terra é praticamente 9,81 m / s ^ 2 para a maioria das latitudes e altitudes (é claro, se você estiver procurando por petróleo no subsolo ou atirando em ICBMs no Pólo Norte, sabendo que a variação na gravidade é muito importante. 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. Há muita física que teria que mudar se g fosse variável.
Tangurena

0

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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.