¿Es alguna vez una buena idea codificar los valores en nuestras aplicaciones? ¿O es siempre lo correcto llamar a estos tipos de valores de forma dinámica en caso de que necesiten cambiar?
¿Es alguna vez una buena idea codificar los valores en nuestras aplicaciones? ¿O es siempre lo correcto llamar a estos tipos de valores de forma dinámica en caso de que necesiten cambiar?
Sí, pero haz que sea objetivo .
Haz:
No:
Lo que me parece extraño de esta pregunta y respuesta hasta ahora es que en realidad nadie ha intentado definir claramente el "código duro" o, lo que es más importante, las alternativas.
tl; dr: Sí, es a veces es una buena idea para los valores de código duro, pero no hay una regla simple para cuándo ; depende completamente del contexto.
La pregunta la reduce a valores , lo que entiendo que significa números mágicos , pero la respuesta a si son o no una buena idea es relativa a para qué se usan realmente
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 había agotado el tiempo antes y alguien planteó el tiempo de espera como un hack en lugar de solucionar el problema de rendimiento subyacente? ¿O es realmente una expectativa conocida y documentada para el tiempo de procesamiento?
Estos no deben ser constantes de números mágicos o , deben ser externalizados en un archivo de configuración o base de datos en algún lugar con un nombre significativo, ya que su valor óptimo está determinado en gran parte o completamente por el entorno en el que la aplicación se está ejecutando en.
Fórmulas matemáticas
Las fórmulas por lo general tienden a ser bastante estáticas, de modo que la naturaleza de los valores constantes no es particularmente importante. El volumen de una pirámide es (1/3) b * h. ¿Nos importa de dónde vienen los 1 o 3? Realmente no. Un comentarista anterior señaló acertadamente que diameter = radius * 2
es probablemente mejor que diameter = radius * RADIUS_TO_DIAMETER_CONVERSION_FACTOR
, pero eso es una falsa dicotomía.
Lo que deberías estar haciendo para este tipo de escenario es crear una función . No necesito saber cómo surgió con la fórmula, pero aún necesito saber para qué sirve . Si, en lugar de cualquiera de las tonterías escritas arriba, escribo volume = GetVolumeOfPyramid(base, height)
, entonces 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 solo son parte de la fórmula.
La clave aquí es, por supuesto, tener las funciones corta y simple . Esto no funciona para funciones con 10 argumentos y 30 líneas de cálculos. Use la composición de funciones o constantes en ese caso.
Dominio / reglas de negocio
Esta es siempre el área gris porque depende de cuál es exactamente el valor. La mayoría de la época, 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 < 19
vs. if Age < LegalDrinkingAge
; probablemente puedas descubrir qué está pasando 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 empresarial 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 las constantes.
La advertencia es que, si está trabajando para el departamento de impuestos, se vuelve realmente, realmente una carga y honestamente no tiene sentido escribir AttachForm(FORM_CODE_FOR_SINGLE_TAXPAYER_FILING_JOINTLY_FOR_DEPRECIATION_ON_ARMPIT_HAIR)
. No va a hacer eso, va a AttachForm("B-46")
porque todos los desarrolladores que hayan trabajado o que trabajarán allí sabrán que "B-46" es el código del formulario para un solo contribuyente que presenta la declaración de impuestos. bla bla: los códigos de formulario son parte del dominio en sí, nunca cambian, por lo que no son realmente números mágicos.
Entonces, tienes que usar constantes con moderación en la lógica de negocios; básicamente tienes que entender si ese "número mágico" es realmente un número mágico o si es un aspecto bien conocido del dominio. Si se trata de un dominio, no lo codifiques a menos que haya una buena posibilidad de que cambie.
Códigos de error e indicadores de estado
Estos son nunca bien para codificar, como puede decirte cualquier bastardo pobre que haya sido golpeado con Previous action failed due to error code 46
. Si su idioma lo admite, debe utilizar un tipo de enumeración. De lo contrario, normalmente tendrá un archivo / módulo completo lleno de constantes que especifican los valores válidos para un tipo de error en particular.
¿No me dejas ver return 42
en un controlador de errores, Capiche? No hay excusas.
Probablemente dejé de lado varios escenarios pero creo que eso cubre la mayoría de ellos.
Entonces, sí, a veces es una práctica aceptable para el código duro. Simplemente no seas perezoso al respecto; debe ser una decisión consciente en lugar de un código descuidado viejo y simple.
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;";
(asumiendo que realmente tiene 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 una máscara de bits de permiso de 255, no la use
const int 8th_bit=255; //or some other obscure naming scheme that equates to 255.
en lugar de utilizar
const int AllowGlobalRead=255;
Por supuesto, junto con las constantes, saber cuándo usar enumeradores. El caso anterior probablemente encajaría bien en uno.
Hay varias razones para asignar un identificador a un número.
Esto nos da criterios para los literales de codificación rígida. Deben ser inmutables, no difíciles de escribir, que ocurren 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.
¿Es siempre una buena idea para codificar? valores en nuestras aplicaciones?
Los valores de código duro solo si los valores están especificados 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 tanto, 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 las constantes cambiantes en las especificaciones requieren una administración de cambios, en la cual, las partes interesadas revisarán el cambio y aprobarán / rechazarán. Nunca sucede durante la noche y toma meses / años para una aprobación. No olvide que muchos desarrolladores utilizan especificaciones (por ejemplo, HTTP), por lo que cambiarlo significa romper millones de sistemas.
Depende de lo que consideres hardcoding. Si intentas evitar todas y cada una de las cosas codificadas, terminas en el territorio de softcoding , y creas un sistema que solo el creador puede administrar (y ese es el código definitivo)
Muchas de las cosas están codificadas en cualquier marco razonable y funcionan. es decir, no hay ninguna razón técnica por la que no pueda cambiar el punto de entrada de una aplicación de C # (estático vacío principal), pero la codificación no crea ningún problema para ningún usuario (excepto el ocasional SOSO )
La regla de oro que utilizo es que todo lo que pueda y vaya a cambiar, sin afectar el estado de todo el sistema, debería ser confugerable.
Así que, IMHO, es una tontería no codificar cosas que nunca cambian (pi, constante gravitacional, una constante en una fórmula matemática - piense en el volumen de una esfera).
También es tonto no codificar cosas o procesos que tendrán un impacto en su sistema que requerirá programación en cualquier caso, es decir, es inútil permitir que el usuario agregue campos dinámicos a un formulario, si algún campo agregado requiera la desarrollador de mantenimiento para entrar y escribir algunos scripts que harán que esa cosa 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 del departamento de TI pueden usarlo, y es un poco más fácil de usar que para hacerlo en Visual Studio.
Por lo tanto, en definitiva, si una cosa debe estar codificada en forma rígida es una función de dos variables:
Recientemente codifiqué una función MySQL para calcular correctamente la distancia entre dos pares de latitud / longitud. No puedes simplemente hacer pitagoro; las líneas de longitud se acercan a medida que la latitud aumenta hacia los polos, por lo que hay un poco de truco peludo involucrado. El punto es que estaba bastante preocupado 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 de latencia / latencia están mucho más juntas en, digamos, la luna. Y mi función subestimaría drásticamente las distancias entre los puntos en Júpiter. Pensé que las posibilidades del sitio web que estoy construyendo al tener una ubicación extraterrestre para ingresar son muy escasas.
He notado que cada vez que puedes extraer datos de tu código, mejora lo que queda. Comienza a notar nuevas refactorizaciones y mejora secciones completas de su código.
Es solo una buena idea trabajar para extraer constantes, no lo consideres una regla estúpida, piénsalo como una oportunidad para codificar mejor.
La mayor ventaja sería la forma en la que podría encontrar constantes similares, ya que es la única diferencia en los grupos de código: abstraerlos en arreglos me ha ayudado a reducir algunos archivos en un 90% de su tamaño y corregir algunas copias & pegar errores mientras tanto.
Todavía no he visto una sola ventaja para no extraer datos.
Bueno, depende de si tu lenguaje está compilado. Si no está compilado, no es un gran problema, simplemente edite el código fuente, incluso si será un poco delicado para un 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 es necesario crear un control deslizante o una interfaz para cambiar dinámicamente su variable, pero lo menos que puedes hacer es un archivo de texto.
Por ejemplo, con mi proyecto de ogro, siempre estoy usando la clase ConfigFile para cargar una variable que he escrito en un archivo de configuración.
Dos ocasiones en que las constantes son (en mi opinión al menos) OK:
Constantes que no 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 la cuadrícula.
Constantes obvias, absolutamente inmutables, precisas, como "número de días por semana". days = weeks * 7
Reemplazar 7
con una constante DAYS_PER_WEEK
casi no proporciona ningún valor.
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 vincularlos claramente a su punto de origen.
He realizado algunos contratos de interconexión donde es necesario rellenar 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 general 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 de tales constantes tuvieran que ser pobladas. En la mayoría de los casos, no proporcionaron un significado o razón, solo dijeron "ponga M aquí" o "ponga 4.10.53.10100.889450.4452 aquí". Tampoco intenté poner un comentario junto a todos ellos habría hecho ilegible el código resultante. Sin embargo, me aseguré de que las secciones de código en las que aparecen estos valores mágicos estén bien aisladas y que sus contenedores (clases, paquetes) tengan el nombre adecuado para apuntar directamente a la especificación que los aplica.
Dicho esto, cuando lo piensas ... todo se trata de hacerlo obvio ...
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, tendrá problemas.
Mayormente no, pero creo que vale la pena señalar que tendrá la mayoría de los 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.
Lea otras preguntas en las etiquetas programming-practices