Codificación rígida.
La codificación rígida incrusta datos como rutas, credenciales o tarifas en el código fuente, de modo que cambiarlos exige editar y recompilar el programa.
El hard coding (codificación rígida) es la práctica de desarrollo de software consistente en incrustar datos directamente en el código fuente de un programa u otro objeto ejecutable, en lugar de obtener los datos de fuentes externas o generarlos en tiempo de ejecución.
Los datos codificados de forma rígida normalmente solo pueden modificarse editando el código fuente y recompilando el ejecutable, aunque pueden cambiarse en memoria o en disco mediante un depurador o un editor hexadecimal.
Los datos codificados de forma rígida son más adecuados para fragmentos de información que no cambian, como las constantes físicas, los números de versión y los elementos de texto estáticos.
Los datos codificados de forma flexible (soft-coded), por el contrario, codifican información arbitraria a través de la entrada del usuario, archivos de texto, archivos INI, respuestas de servidores HTTP, archivos de configuración, bases de datos y argumentos de línea de comandos, y se determinan en tiempo de ejecución. Las macros del preprocesador y las constantes definidas en un archivo de cabecera o un módulo aparte no son codificación flexible en este sentido: dan al valor un nombre y un único lugar, pero sigue fijándose en tiempo de compilación, por lo que cambiarlo exige recompilar.
Descripción general
La codificación rígida exige que el código fuente del programa se modifique cada vez que cambian los datos de entrada o el formato deseado, cuando podría ser más cómodo para el usuario final cambiar el detalle por algún medio externo al programa.
La codificación rígida a menudo es necesaria, pero también puede considerarse un antipatrón. Es posible que los programadores no tengan resuelta una solución de interfaz de usuario dinámica para el usuario final, pero aun así deban entregar la funcionalidad o publicar el programa. Esto suele ser temporal, pero resuelve, a corto plazo, la presión por entregar el código. Más adelante se realiza la codificación flexible para permitir que un usuario pase parámetros que le den al usuario final una forma de modificar los resultados o el desenlace.
El término "hard-coded" (codificado de forma rígida) se utilizó inicialmente como una analogía con el cableado fijo de circuitos, y pretendía transmitir la inflexibilidad que resulta de su uso en el diseño y la implementación de software. En el contexto de los entornos de desarrollo colaborativo extensibles en tiempo de ejecución, como los MUD, la codificación rígida también se refiere al desarrollo del motor central del sistema, responsable de las tareas de bajo nivel y de ejecutar los scripts, en contraposición a la codificación flexible, que consiste en desarrollar los scripts de alto nivel que el sistema interpreta en tiempo de ejecución, con valores procedentes de fuentes externas, como archivos de texto, archivos INI, bases de datos, argumentos de línea de comandos, respuestas de servidores HTTP, archivos de configuración y la entrada del usuario. En este caso, el término no es peyorativo y se refiere al desarrollo en general, en lugar de específicamente a la incrustación de datos de salida.
Puertas traseras
Codificar las credenciales de forma rígida es una forma habitual de crear una puerta trasera. Las credenciales codificadas de forma rígida normalmente no son visibles en los archivos de configuración ni en la salida de los comandos de enumeración de cuentas, y los usuarios no pueden cambiarlas ni eludirlas con facilidad. Si se descubre, un usuario podría desactivar esa puerta trasera modificando y reconstruyendo el programa a partir de su código fuente (si el código está disponible públicamente), descompilando o realizando ingeniería inversa del software, editando directamente el código binario del programa o instaurando una comprobación de integridad (como firmas digitales, antimanipulación y antitrampas) para impedir el acceso inesperado, pero tales acciones suelen estar prohibidas por un acuerdo de licencia de usuario final.
Ruta de instalación fija
Si un programa de Windows está programado para asumir que siempre se instala en C:\Program Files\Appname y alguien intenta instalarlo en una unidad diferente por razones de espacio u organización, puede que no se instale o que no se ejecute tras la instalación. Puede que este problema no se identifique en el proceso de pruebas, ya que el usuario medio instala en la unidad y el directorio predeterminados, y las pruebas podrían no incluir la opción de cambiar el directorio de instalación. Sin embargo, es aconsejable que los programadores y desarrolladores no fijen la ruta de instalación de un programa, ya que la ruta de instalación predeterminada depende del sistema operativo, de la versión del SO y de las decisiones del administrador de sistemas. Por ejemplo, muchas instalaciones de Microsoft Windows usan la unidad C: como su disco duro principal, pero esto no está garantizado.
Carpetas especiales
Algunos sistemas operativos Windows tienen las denominadas carpetas especiales que organizan los archivos de forma lógica en el disco duro. Hay problemas que pueden surgir relacionados con la codificación rígida:
Ruta del perfil
Algunos programas de Windows codifican de forma rígida la ruta del perfil a ubicaciones definidas por el desarrollador, como C:\Documents and Settings\Username, la ruta predeterminada en Windows 2000 y Windows XP, o C:\Users\Username, la predeterminada desde Windows Vista. Una ruta así falla cuando el programa se ejecuta en otra versión de Windows o cuando el perfil se almacena en una red o se reubica de otro modo. La forma correcta de obtenerla es llamar a la función GetUserProfileDirectory o resolver la variable de entorno %userprofile%. Otra suposición que los desarrolladores suelen hacer es que el perfil se encuentra en un disco duro local.
Ruta de la carpeta Mis Documentos
Algunos programas de Windows codifican de forma rígida la ruta a Mis Documentos como ProfilePath\My Documents. Estos programas funcionarían en máquinas que ejecutan la versión en inglés, pero en las versiones localizadas de Windows esta carpeta normalmente tiene un nombre diferente. Por ejemplo, en las versiones en italiano la carpeta My Documents se llama Documenti. Es posible que My Documents también se haya reubicado mediante la Redirección de Carpetas en las Directivas de Grupo en Windows 2000 o posterior. La forma adecuada de obtenerla es llamar a la función SHGetKnownFolderPath (SHGetFolderPath en versiones anteriores a Windows Vista).
Solución
Una referencia indirecta, como una variable dentro del programa llamada "FileName", podría ampliarse accediendo a una ventana de diálogo de "buscar archivo", y el código del programa no tendría que cambiarse si el archivo se moviera.
La codificación rígida es especialmente problemática al preparar el software para su traducción a otros idiomas.
En muchos casos, un único valor codificado de forma rígida, como el tamaño de un arreglo, puede aparecer varias veces dentro del código fuente de un programa. Esto sería un número mágico. Esto suele provocar un error en el programa si se modifican algunas de las apariciones del valor, pero no todas. Un error así es difícil de encontrar y puede permanecer en el programa durante mucho tiempo. Puede ocurrir un problema similar si el mismo valor codificado de forma rígida se utiliza para más de un valor de parámetro, por ejemplo, un arreglo de 6 elementos y una longitud mínima de cadena de entrada de 6. Un programador podría cambiar por error todas las instancias del valor (a menudo usando la función de buscar y reemplazar de un editor) sin revisar el código para ver cómo se utiliza cada instancia. Ambas situaciones se evitan definiendo constantes, que asocian nombres a los valores, y usando los nombres de las constantes en cada aparición dentro del código.
Un caso importante de codificación rígida es cuando las cadenas se colocan directamente en el archivo, lo que obliga a los traductores a editar el código fuente para traducir un programa. (Existe una herramienta llamada gettext que permite dejar las cadenas en los archivos, pero deja que los traductores las traduzcan sin cambiar el código fuente; en efecto, "descodifica" las cadenas.)
Codificación flexible
La codificación flexible (soft coding) es un término de programación que se refiere a obtener un valor o una función de algún recurso externo, como archivos de texto, archivos INI, archivos de configuración, argumentos de línea de comandos, bases de datos, entrada del usuario y respuestas de servidores HTTP. Es lo opuesto a la codificación rígida, que se refiere a codificar valores y funciones en el código fuente.
Práctica de programación
Evitar la codificación rígida de valores que se modifican con frecuencia es una buena práctica de programación. Los usuarios del software deberían poder personalizarlo según sus necesidades, dentro de lo razonable, sin tener que editar el código fuente del programa. De forma similar, los programadores cuidadosos evitan los números mágicos en su código para mejorar su legibilidad y facilitar el mantenimiento. Por lo general, estas prácticas no se denominan codificación flexible.
El término se usa generalmente cuando la codificación flexible se convierte en un antipatrón. Abstraer demasiados valores y características puede introducir más complejidad y problemas de mantenimiento de los que supondría cambiar el código cuando sea necesario. La codificación flexible, en este sentido, apareció en un artículo de The Daily WTF.
Problemas potenciales
En el extremo, los programas con codificación flexible desarrollan sus propios lenguajes de scripting mal diseñados e implementados, y archivos de configuración que requieren conocimientos avanzados de programación para editarlos. Esto puede llevar a la creación de utilidades para ayudar a configurar el programa original, y estas utilidades a menudo acaban teniendo ellas mismas codificación flexible.
La frontera entre una configurabilidad adecuada y una codificación flexible problemática cambia con el estilo y la naturaleza de un programa. Los programas de código cerrado deben ser muy configurables, ya que el usuario final no tiene acceso al código fuente para hacer cambios. El software interno y el software de distribución limitada pueden ser menos configurables, ya que distribuir copias modificadas es más sencillo. Las aplicaciones web hechas a medida suelen funcionar mejor con una configurabilidad limitada, ya que modificar los scripts rara vez es más difícil que modificar un archivo de configuración.
Para evitar la codificación flexible, considere el valor que tiene para el usuario final cualquier flexibilidad adicional que proporcione, y compárelo con la mayor complejidad y los costes de mantenimiento continuo asociados que conlleva la configurabilidad añadida.
Lograr flexibilidad
Existen varios patrones de diseño legítimos para lograr la flexibilidad que la codificación flexible intenta proporcionar. Una aplicación que requiere más flexibilidad de la apropiada para un archivo de configuración puede beneficiarse de la incorporación de un lenguaje de scripting. En muchos casos, el diseño adecuado es un lenguaje específico de dominio integrado en un lenguaje de scripting establecido. Otro enfoque es trasladar la mayor parte de la funcionalidad de una aplicación a una biblioteca, proporcionando una API para escribir rápidamente aplicaciones relacionadas.
Ejemplo
Este módulo incrusta en su código fuente la dirección de la base de datos, las credenciales y el tipo de IVA. Ejecutar la misma compilación contra una base de datos de pruebas, rotar la contraseña o adaptarse a un cambio fiscal obliga a editar y volver a desplegar el código, y la contraseña acaba en el control de versiones.
def connect():
return Database(host="10.0.0.12", user="admin", password="s3cr3t!")
def price_with_vat(amount):
return amount * 1.2
Los valores que difieren entre entornos o cambian con el tiempo ahora proceden del entorno; el código conserva solo la lógica (véase también Configuración codificada de forma rígida).
import os
from dataclasses import dataclass
@dataclass(frozen=True)
class Settings:
db_host: str
db_user: str
db_password: str
vat_rate: float
@classmethod
def from_env(cls) -> "Settings":
return cls(
db_host=os.environ["DB_HOST"],
db_user=os.environ["DB_USER"],
db_password=os.environ["DB_PASSWORD"],
vat_rate=float(os.environ["VAT_RATE"]),
)
def connect(settings: Settings):
return Database(host=settings.db_host, user=settings.db_user, password=settings.db_password)
def price_with_vat(amount, settings: Settings):
return amount * (1 + settings.vat_rate)
Adaptado del artículo de Wikipedia “Hard coding” (revisión 1355219913), disponible bajo la licencia CC BY-SA 4.0; el texto ha sido traducido y editado, y se han añadido ejemplos.