¿Alguna vez es una buena idea codificar valores en nuestras aplicaciones?

45

¿Alguna vez es una buena idea codificar valores en nuestras aplicaciones? ¿O es siempre lo correcto llamar a este tipo de valores dinámicamente en caso de que necesiten cambiar?

Eduardo
fuente
2
un parámetro de configuración te ayudaría
Gopi
54
Nunca se sabe cuándo pipodría cambiar el valor de ...
Gabe
12
Hombre, supongo que personas como @gabe son la razón por la que esta es una "Regla". Si repite 3.14 en 20 lugares en su código y luego descubre que realmente necesita más precisión, está jodido. No me di cuenta de que esto no era obvio.
Bill K
17
Eso fue un poco grosero, @Bill. @Gabe claramente estaba bromeando, pero aparte de eso, la pregunta era sobre la codificación rígida vs. los parámetros de configuración, no el uso de números mágicos constantes vs. repetidos en múltiples lugares.
David Conrad
1
Sí, la codificación rígida puede ser una buena idea a veces. Vea el artículo de Wikipedia sobre el antipatrón "Softcoding".
user16764

Respuestas:

64

Sí, pero hazlo obvio .

Hacer:

  • usar constantes
  • usar un nombre descriptivo de variable

No:

Jonathan Khoo
fuente
44
¿Cuál es más limpio diameter = 2 * radiuso diameter = RADIUS_TO_DIAMETER_FACTOR * radius? De hecho, hay casos en los que un número mágico puede ser una mejor solución.
Joonas Pulakka
55
No puedo estar de acuerdo con esta respuesta lo suficiente. Tiendo a pensar en la programación como si fuera un novelista. Usted cuenta su historia a través del código y, si la gente no puede entender la lógica, hace que su código no tenga valor en mi opinión. Es por eso que las convenciones de nomenclatura bien pensadas son esencialmente para facilitar la lectura. Además, no hay una buena razón para usar números mágicos. Mediante el uso de números mágicos, elimina el "por qué" de la ecuación y hace que sea más difícil de entender. Por ejemplo: "diámetro = 2 * radio" ¿Para qué son los dos? Este "diámetro = RADIUS_TO_DIAMETER_FACTOR * radio" tiene mucho más sentido.
chrisw
99
diámetro = 2 * radio es directamente de matemáticas de secundaria. La razón para no nombrar el "2" es que tener un valor de cualquier otra cosa requeriría un cambio en las leyes de la física o las matemáticas, o ambas. (Por otro lado, nombrar Pi o Plancks constante es un buen movimiento para facilitar la lectura).
rapid_now
8
@Joonas: Pfft. ¿Seguramente quieres decir diameter = radius << 1? Supongo que eso también podría ser diameter = radius << RADIUS_TO_DIAMETER_BITS_TO_SHIFT.
Ant
44
¿Qué tal un pocodiameter = radius.toDiameter()
Carson Myers
27

Lo que me parece extraño de estas preguntas y respuestas hasta ahora es que nadie ha intentado definir claramente "código duro" o, lo que es más importante, las alternativas.

tl; dr: Sí, a veces es una buena idea codificar valores, pero no existe una regla simple sobre cuándo ; Depende completamente del contexto.

La pregunta lo reduce a valores , que considero que significan números mágicos , ¡pero la respuesta a si son una buena idea es relativa a lo que realmente se usan!

Varios ejemplos de valores "codificados" son:

  • Valores de configuración

    Me estremezco cada vez que veo declaraciones como command.Timeout = 600. ¿Por qué 600? ¿Quién decidió eso? ¿Se estaba agotando el tiempo antes y alguien planteó el tiempo de espera como un truco en lugar de solucionar el problema de rendimiento subyacente? ¿O es realmente alguna expectativa conocida y documentada para el tiempo de procesamiento?

    Estos no deberían ser números mágicos o constantes, deberían estar externalizados en un archivo de configuración o base de datos en algún lugar con un nombre significativo, porque su valor óptimo está determinado en gran medida o completamente por el entorno en el que se ejecuta la aplicación.

  • Fórmulas matemáticas

    Las fórmulas generalmente tienden a ser bastante estáticas, de modo que la naturaleza de los valores constantes en el interior no es realmente particularmente importante. El volumen de una pirámide es (1/3) b * h. ¿Nos importa de dónde vino el 1 o el 3? Realmente no. Un comentarista anterior señaló acertadamente que diameter = radius * 2probablemente sea mejor que diameter = radius * RADIUS_TO_DIAMETER_CONVERSION_FACTOReso, pero eso es una falsa dicotomía.

    Lo que debe hacer para este tipo de escenario es crear una función . No necesito saber cómo se te ocurrió la fórmula, pero aún necesito saber para qué sirve . Si, en lugar de cualquiera de las tonterías escritas anteriormente, escribo volume = GetVolumeOfPyramid(base, height), de repente todo se vuelve mucho más claro, y está perfectamente bien tener números mágicos dentro de la función ( return base * height / 3) porque es obvio que son solo parte de la fórmula.

    La clave aquí es, por supuesto, tener funciones cortas y simples . Esto no funciona para funciones con 10 argumentos y 30 líneas de cálculos. Utilice la composición de funciones o constantes en ese caso.

  • Dominio / reglas comerciales

    Esta siempre es el área gris porque depende de cuál sea exactamente el valor. La mayoría de las veces, estos números mágicos particulares son candidatos para convertirse en constantes, porque eso hace que el programa sea más fácil de entender sin complicar la lógica del programa. Considere la prueba if Age < 19vs. if Age < LegalDrinkingAge; probablemente puedas descubrir qué está sucediendo sin la constante, pero es más fácil con el título descriptivo.

    Estos también pueden convertirse en candidatos para la abstracción de funciones, por ejemplo function isLegalDrinkingAge(age) { return age >= 19 }. Lo único es que a menudo su lógica de negocios es mucho más complicada que eso, y puede que no tenga sentido comenzar a escribir docenas de funciones con 20-30 parámetros cada una. Si no hay una abstracción clara basada en objetos y / o funciones, entonces está bien recurrir a constantes.

    La advertencia es que, si está trabajando para el departamento de impuestos, se vuelve realmente muy pesado y honestamente inútil escribir AttachForm(FORM_CODE_FOR_SINGLE_TAXPAYER_FILING_JOINTLY_FOR_DEPRECIATION_ON_ARMPIT_HAIR). No vas a hacer eso, lo harás AttachForm("B-46")porque cada desarrollador que haya trabajado o vaya a trabajar allí sabrá que "B-46" es el código de formulario para un solo contribuyente que presenta bla, bla, bla. los códigos de forma son parte del dominio en sí, nunca cambian, por lo que no son realmente números mágicos.

    Por lo tanto, debe usar las constantes con moderación en la lógica empresarial; básicamente debes entender si ese "número mágico" es realmente un número mágico o si es un aspecto bien conocido del dominio. Si es dominio, entonces no lo codificas a menos que haya una muy buena posibilidad de que cambie.

  • Códigos de error y banderas de estado

    Esto nunca está bien para el código duro, como Previous action failed due to error code 46puede decirle cualquier bastardo pobre que haya sido golpeado . Si su idioma lo admite, debería usar un tipo de enumeración. De lo contrario, generalmente tendrá un archivo / módulo completo lleno de constantes que especifican los valores válidos para un tipo de error en particular.

    ¿Nunca me dejas ver return 42en un controlador de errores, capiche? No hay excusas.

Probablemente omití varios escenarios, pero creo que eso cubre la mayoría de ellos.

Entonces, sí, a veces es una práctica aceptable codificar cosas. Simplemente no seas perezoso al respecto; debería ser una decisión consciente en lugar de un viejo código descuidado.

Aaronaught
fuente
Gracias por el buen desglose! - La mayoría de las personas no piensan en todas las opciones que agregaría "Configuración del entorno" - Creo que deben evitarse (no codificadas), ya que la mayoría de los datos deben colocarse en un archivo de configuración o base de datos. Esto sigue el principio de "mantener los datos y la lógica separados" que es un pilar de MVC o MVVM. string TestServerVar = "foo"; string ProdServerVal = "barra";
m1m1k
7

Hay varias razones para asignar un identificador a un número.

  • Si el número puede cambiar, debe tener un identificador. Es mucho más fácil encontrar NUMBER_OF_PLANETS que buscar cada instancia de 9 y considerar si debe cambiarse a 8. (Tenga en cuenta que las cadenas visibles por el usuario podrían tener que cambiar si el software alguna vez tiene que usarse en un idioma diferente, y eso es algo difícil de predecir de antemano)
  • Si el número es difícil de escribir de alguna manera. Para constantes como pi, es mejor dar una definición de máxima precisión que volver a escribirla en varios lugares, posiblemente de manera inexacta.
  • Si el número ocurre en diferentes lugares. No debería tener que mirar dos usos de 45 en funciones adyacentes y preguntarse si significan lo mismo.
  • Si el significado no es reconocible al instante. Es seguro asumir que todo el mundo sabe lo que es 3.14159265 ... No es seguro asumir que todos reconocerán la constante gravitacional, o incluso pi / 2. ("Todos" aquí depende de la naturaleza del software. Se puede esperar que los programadores de sistemas conozcan la representación octal de los bits de permiso de Unix o similares. En el software de arquitectura naval / marina, verificar el número Froude de un casco propuesto y la velocidad para ver si es 1.1 o superior podría explicarse perfectamente a cualquiera que debería estar trabajando en ello).
  • Si el contexto no es reconocible. Todo el mundo sabe que hay 60 minutos en una hora, pero multiplicar o dividir por 60 puede no estar claro si no hay indicios inmediatos de que la cantidad sea un valor de tiempo o un valor de tasa.

Esto nos da criterios para codificar literales. Deben ser inmutables, no difíciles de escribir, ocurrir en un solo lugar o contexto, y con un significado reconocible. No tiene sentido definir 0 como ARRAY_BEGINNING, por ejemplo, o 1 como ARRAY_INCREMENT.

David Thornley
fuente
5

Como una adición a otras respuestas. Use constantes para cadenas cuando sea posible. Por supuesto, no quieres tener

const string server_var="server_var";

pero deberías tener

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

(suponiendo que realmente tenga una consulta en la que desea obtener todos los resultados de una tabla específica, siempre)

Aparte de eso, use constantes para cualquier número que no sea 0 (generalmente). Si necesita un permiso de máscara de bits de 255, no use

const int 8th_bit=255; //or some other obscure naming scheme that equates to 255.

en su lugar usa

const int AllowGlobalRead=255;

Por supuesto, junto con las constantes, sepa cuándo usar enumeradores. El caso anterior probablemente encajaría bien en uno.

Earlz
fuente
typedef enum {state_0 = 0, state_1 = 1, state_2 = 2, ...} ... No te rías, lo he visto hecho. ¡Golpea a esa persona alrededor de la cabeza con un pez mojado!
rápidamente_abr
@ muy bien, por supuesto, querrías algo más comotypedef enum {init_state=0, parse_state=1, evaluation_state=2, ... }
Earlz
66
THIS_NAMING_CONVENTION_IS_RECOMMENDED_FOR_CONSTANTS
StuperUser
44
Para las cadenas, no solo quieres constantes. Desea colocar cualquier cadena visible para el usuario en algún tipo de archivo de recursos (los detalles dependerán de su plataforma) para que pueda cambiar a otro idioma fácilmente.
David Thornley
También es posible que desee pegar cadenas relacionadas con la lógica empresarial (como consultas SQL) en un archivo de recursos con algún tipo de cifrado u ofuscación. Eso evitará que los usuarios "curiosos" realicen ingeniería inversa de su lógica (o esquema de base de datos).
TMN
4

Depende de lo que consideres hardcoding. Si intenta evitar todas las cosas codificadas, termina en un territorio de codificación suave y crea un sistema que solo el creador puede administrar (y ese es el código rígido definitivo)

Muchas cosas están codificadas en cualquier marco razonable y funcionan. es decir, no hay una razón técnica por la cual no debería poder cambiar el punto de entrada de una aplicación C # (estático vacío principal), pero la codificación rígida no crea ningún problema para ningún usuario (excepto la pregunta ocasional de SO )

La regla general que uso es que cualquier cosa que pueda cambiar y que cambie, sin afectar el estado de todo el sistema, debe ser confusa.

Entonces, en mi humilde opinión, es una tontería no codificar cosas que nunca están cambiando (pi, constante gravitacional, una constante en una fórmula matemática - piense en el volumen de una esfera).

Además, es una tontería no codificar cosas o procesos que tendrán un impacto en su sistema que requerirá programación en cualquier caso, es decir, es un desperdicio permitir que el usuario agregue campos dinámicos a un formulario, si algún campo agregado requeriría que el desarrollador de mantenimiento entra y escribe un guión que haga que eso funcione. También es estúpido (y lo he visto varias veces en entornos empresariales) crear alguna herramienta de configuración, por lo que nada está codificado, sin embargo, solo los desarrolladores en el departamento de TI pueden usarlo, y es solo un poco más fácil de usar que para hacerlo en Visual Studio.

Entonces, en resumen, si una cosa debe estar codificada es una función de dos variables:

  • cambiará el valor
  • ¿Cómo afectará un cambio en el valor al sistema?
SWeko
fuente
4

¿Alguna vez es una buena idea codificar valores en nuestras aplicaciones?

Codifico los valores solo si los valores se especifican en la Especificación (en una versión final de la especificación), por ejemplo, la respuesta HTTP OK siempre será 200(a menos que cambie en el RFC), por lo que verá (en algunos de mis códigos ) constantes como:

public static final int HTTP_OK = 200;

De lo contrario, almaceno constantes en el archivo de propiedades.

La razón por la que especifiqué las especificaciones es que el cambio de constantes en las especificaciones requiere una gestión de cambios, en la cual los interesados ​​revisarán el cambio y lo aprobarán / desaprobarán. Nunca sucede de la noche a la mañana y toma meses / años para su aprobación. No olvide que muchos desarrolladores usan especificaciones (por ejemplo, HTTP), por lo que cambiarlo significa romper millones de sistemas.

Buhake Sindi
fuente
3
  • Si el valor puede cambiar y, de hecho, puede cambiar, codifíquelo siempre que sea posible siempre que el esfuerzo involucrado no exceda el rendimiento esperado
  • algunos valores no pueden ser codificados por software; seguir las pautas de Jonathan en esos casos (raros)
Steven A. Lowe
fuente
3

Me di cuenta de que cada vez que puede extraer datos de su código, mejora lo que queda. Comienza a notar nuevas refactorizaciones y mejora secciones enteras de su código.

Es una buena idea trabajar para extraer constantes, no lo considere una regla estúpida, piense en ello como una oportunidad para codificar mejor.

La mayor ventaja sería la forma en que podría encontrar constantes similares como la única diferencia en los grupos de código: abstraerlos en matrices me ha ayudado a reducir algunos archivos en un 90% de su tamaño y, mientras tanto, corregir algunos errores de copiar y pegar .

Todavía tengo que ver una ventaja única para no extraer datos.

Bill K
fuente
2

Recientemente codifiqué una función MySQL para calcular correctamente la distancia entre dos pares lat / long. No puedes simplemente hacer pitágorus; las líneas de longitud se acercan a medida que la latitud aumenta hacia los polos, por lo que hay un poco de trigonometría complicada. El punto es que estaba bastante dividido acerca de si codificar el valor que representa el radio de la Tierra en millas.

Terminé haciéndolo, aunque el hecho es que las líneas lat / lng están mucho más juntas, digamos, en la luna. Y mi función subestimaría drásticamente las distancias entre puntos en Júpiter. Me imaginé que las probabilidades de que el sitio web que estoy construyendo tenga una ubicación extraterrestre ingresada son bastante escasas.

Dan Ray
fuente
Sí, probablemente, pero ¿qué pasa con google.com/moon
Residuo
1

Bueno, depende de si tu idioma está compilado. Si no está compilado, no es gran cosa, solo edita el código fuente, incluso si será un poco delicado para un no programador.

Si está programando con un lenguaje compilado, esto claramente no es una buena idea, porque si las variables cambian, tiene que volver a compilar, lo que es una gran pérdida de tiempo si desea ajustar esta variable.

No necesita hacer un control deslizante o una interfaz para cambiar dinámicamente su variable, pero lo menos que puede hacer es un archivo de texto.

Por ejemplo, con mi proyecto ogro, siempre estoy usando la clase ConfigFile para cargar una variable que he escrito en un archivo de configuración.

jokoon
fuente
1

Dos ocasiones donde las constantes son (al menos en mi opinión) OK:

  1. Constantes que se relacionan con nada más; puedes cambiar esas constantes cuando quieras sin tener que cambiar nada más. Ejemplo: el ancho predeterminado de una columna de cuadrícula.

  2. Absolutamente inmutables, precisas, constantes obvias, como "número de días por semana". days = weeks * 7Reemplazar 7con una constante DAYS_PER_WEEKapenas proporciona ningún valor.

usuario281377
fuente
0

Estoy completamente de acuerdo con Jonathan, pero como todas las reglas hay excepciones ...

"Número mágico en la especificación: Número mágico en el código"

Básicamente establece que cualquier número mágico que permanezca en la especificación después de intentos razonables de obtener un contexto descriptivo para ellos debe reflejarse como tal en el código. Si los números mágicos permanecen en el código, se deben hacer todos los esfuerzos para aislarlos y hacer que estén claramente vinculados a su punto de origen.

He realizado algunos contratos de interfaz donde es necesario completar mensajes con valores asignados desde la base de datos. En la mayoría de los casos, el mapeo es bastante sencillo y encajaría en las líneas de guía generales de Jonathan, pero he encontrado casos en los que la estructura del mensaje de destino era simplemente horrible. Más del 80% de los valores que debían transmitirse en la estructura eran constantes aplicadas por la especificación del sistema distante. Esto, junto con el hecho de que la estructura del mensaje era gigantesca, hizo que MUCHAS constantes tuvieran que ser pobladas. En la mayoría de los casos no proporcionaron un significado o razón, solo dijeron "pon M aquí" o "pon 4.10.53.10100.889450.4452 aquí". Tampoco intenté poner un comentario al lado de todos ellos, habría hecho que el código resultante fuera ilegible.

Dicho esto, cuando lo piensas ... se trata básicamente de hacerlo obvio ...

Newtopian
fuente
0

Si está codificando el valor de la constante gravitacional de la Tierra, a nadie le importará. Si codifica la dirección IP de su servidor proxy, tiene problemas.

jwenting
fuente
1
Es posible que necesite más precisión para la constante gravitacional de la Tierra, por lo que codificarla varias veces puede ocasionar problemas.
user281377
1
Peter Noone? ¿De los ermitaños de Herman?
David Conrad
La aceleración gravitacional en la Tierra es de aproximadamente 9.81 m / s ^ 2 para la mayoría de las latitudes y altitudes (por supuesto, si está buscando petróleo bajo tierra o disparando ICBM sobre el Polo Norte, saber la variación en la gravedad es muy importante para muchos más decimales), con la aceleración gravitacional en otros planetas siendo un número diferente, pero que yo sepa, la constante gravitacional es constante alrededor del universo. Hay mucha física que tendría que cambiar si g fuera variable.
Tangurena
0

Principalmente no, pero creo que vale la pena señalar que tendrá más problemas cuando comience a duplicar el valor codificado. Si no lo duplica (por ejemplo, úselo solo una vez en la implementación de una clase), entonces no usar una constante podría estar bien.


fuente