Read time: 9 mins
Configuraciones

Configurar una aplicación es la manera en que los programadores le damos al usuario capacidades para que el programa sea más potente por sí mismo, sin depender de que tengamos que hacer más cambios y sin tener que programarlos.

Es, de entrada, la puerta con la que el usuario se puede empoderar para hacer un mejor uso de la información que el programa le entregará. Y por eso es una parte importante y esencial de un software bien implementado.

Cuando se diseña un sistema, se tienen que tomar muchas decisiones, y hacerse muchas preguntas. Respecto a la configuración, la primera sería:

 

¿Qué SÍ configurar?

Y la respuesta a esto, claro, depende de muchas cosas: desde qué tanto deseas darle al usuario la capacidad de controlar su propio software, hasta incluso el estilo propio con que usualmente le proporciones configuraciones a las aplicaciones.

Igual depende del tipo de software o aplicación que estés escribiendo. Por ejemplo, ¿estás programando para Unix? la respuesta sería que deberías configurar prácticamente todo. Lo cual no siempre es una buena sugerencia, depende el contexto. Por eso cambiemos mejor la pregunta:

¿Qué NO configurar?

Eric S. Raymond lo aclara en su libro "The Art of Unix Programming", siguiendo tres lineamientos:

  1. Primero que nada, no configures lo que puedas detectar en automático. Usa algún mecanismo de autodetección, quizá puedas usar métodos alternativos para autodetectar en runtime hasta que uno funcione. Así no molestas al usuario pidiéndole la información, ni llenas una interfaz de configuración con más campos que llenar.
  2. Segundo, no uses configuraciones para optimizar. Es tu trabajo que el programa economice, no del usuario. A menos que se trate justamente de eso, no pongas configuraciones para que el usuario determine si cierta parte del sistema lo hará más o menos eficiente según el valor configurado.
  3. Por último, no pongas configuración a algo que puedes resolver con otro programa que ayude al tuyo a hacer el trabajo. Si lo haces, estarás agregándole complejidad a tu programa. Que el tuyo sea lo mas sencillo posible, y que el script que coordina tu programa con los otros se encargue de eso.

Otras preguntas guía:

  • ¿Puedo dejar este feature fuera? Menos features = menos posibles configuraciones. ¿Por qué agobiarse llenando el manual y cargando al usuario?
  • ¿Podría cambiarse el comportamiento normal del programa de forma inocua para que cierta opción sea innecesaria?
  • Si la opción es meramente estética, quizá sea mejor dejarla fuera. ¿No deberías dejar de pensar en hacer la interfaz configurable, y en su lugar hacerla correcta?
  • El comportamiento que esta opción habilita, ¿no cabría mejor en un programa separado?

 

Una vez decidido qué configurar, pasemos ahora sí a la parte técnica...

¿En dónde se configura?

Depende por supuesto de muchos factores: del sistema que estás programando, pero también del sistema operativo en donde éste se ejecutará. Tomemos, solo como ejemplo, el estilo Unix:

Se utiliza una estructura jerárquica para configurar. Se tiene un lugar genérico para las configuraciones, y niveles cada vez más específicos que sobreescriben los valores de los lugares más abajo en la jerarquía:

  • /etc - en este directorio viven los archivos de configuración de todo el sistema. En este caso habría un archivo de configuración general de TODO el programa para uso de TODOS los usuarios. Cada archivo de configuración contendría, en algún formato específico, una serie de valores para ciertas constantes de configuración del programa.
  • variables de entorno a nivel sistema - se trata de variables con valores específicos que viven en memoria RAM a través del sistema de variables de entorno. En este caso aplican para todos los usuarios del sistema, remplazando lo que sea que tengan los archivos de /etc.
  • archivos de configuración en el directorio $HOME - son propios de cada usuario. Viven en archivos pero en los directorios personales de cada usuario del sistema. El formato podría ser similar al de los archivos en /etc, pero sus valores prevalecen sobre las configuraciones a nivel sistema (de /etc y de variables de entorno).
  • variables de entorno a nivel usuario - son propias de cada usuario, viven en RAM, y remplazan las configuraciones anteriores.
  • switches y argumentos del programa - se proporcionan al invocar el programa, con parametros o argumentos de línea de comandos. Remplazan cualquier otra configuración anterior.

Cada variable de configuración se busca desde el primer nivel hasta el último. Si no se encuentra en un nivel, se continua. Si se encuentra en uno, se toma ese valor, pero si se encuentra en uno superior, sobre-escribe las anteriores ocurrencias.

También, aunque no siempre es recomendable usarlo para producción, se pueden dejar hardcodeadas ciertas configuraciones por default. En caso de no ser encontradas en ninguno de los niveles arriba mencionados, se usa el default. Si el default es suficientemente razonable, se puede usar. Sino, sólo sirve para que el programa no truene a causa de una configuración faltante.

 

¿Cuándo se usan las configuraciones en el programa?

Bien, ya tienes las configuraciones colocadas en su sitio. ¿Cuándo se usan? Es decir ¿cuándo se configura el programa? Igual hay distintos estilos. Básicamente:

  • Al inicio: al arrancar el programa, se cargan las configuraciones, por ejemplo usando la jerarquía arriba mencionada. Esto implica que si las configuraciones deben cambiar, entonces el programa se debe reiniciar.
  • En runtime: conforme se van necesitando las configuraciones, se leen las mismas, por ejemplo también usando la jerarquía arriba mencionada. Esto tiene el posible beneficio de que se pueden modificar las configuraciones sin necesidad de reiniciar el programa. Sin embargo, las configuraciones pasadas por línea de comandos no pueden recargarse así, el programa si debe reiniciarse en estos casos, por obvias razones.

 

¿Cómo se configura?

Hay muchas formas, técnicas y estilos. Por mencionar algunos:

  • Puedes tener tus configuraciones hardcodeadas y ya. Olvídate de esquemas, jerarquías o lo que sea. Las opciones van en el código. Obviamente esto no es configurar, puesto que en realidad el usuario no puede cambiar estos parámetros (a menos que le des una interfaz para que cambie los valores, pero sólo mientras dure la ejecución del programa o sesión, al reiniciar todo vuelve a los valores originales). En programas donde en realidad no necesitas demasiada flexibilidad, o no cuentas con la infraestructura, puede ser suficiente.
  • O puedes usar a secas la estructura jerárquica que mencioné arriba. Es un modelo bastante sólido y uniforme, estándar para muchas aplicaciones en Unix, que además se puede migrar de una u otra manera a otros sistemas.
  • Otra forma cada día más común consiste en tener un servidor de configuraciones. En un mundo donde cada día son más comunes los servicios, esta opción es potente, flexible y además proporciona mecanismos que se podrían usar para configurar deployeos de tu aplicación en distintos ambientes (estilo desarrollo-pruebas-calidad-producción).

 

Ejemplo

Veamos un ejemplo, en un software que nosotros desarrollamos: MambuPy, una librería en Python para acceder a los servicios de Mambu. Su código fuente lo pueden consultar aquí. (Ahorita que vamos revisando cómo usamos la configuración, quizá quieras echarle un ojo al código de MambuPy/mambuconfig.py)

Anteriormente, antes de liberar nuestro proyecto, teníamos todas las configuraciones hardcodeadas. Eso nos resultaba fácil, hasta cierto punto, porque eramos los únicos usuarios del software. Cuando liberamos, pusimos MambuPy disponible para instalar desde pip, la forma más sencilla y práctica para librerías en Python. Siendo así, configuraciones hardcodeadas son la peor idea, no le pediríamos a nuestros usuarios (mayormente programadores) que se metieran a las tripas donde Python instala sus paquetes vía pip para editar las configuraciones ahí. Así que pasamos al siguiente esquema, que se mantiene al menos a día de hoy (v 1.3.6):

  • mambuconfig lee la configuración de una estructura jerárquica como la siguiente:
    • los defaults de todas las constantes de configuración están hardcodeados básicamente para que los programas que utilicen MambuPy no truenen a causa de una configuración inexistente. Preferimos que se lance un error del tipo 'no puedo contactar con el dominio domain.mambu.com' a KeyError 'No existe la llave apiurl'.
    • en /etc se busca el archivo mambupy.rc, para las configuraciones globales de todo el sistema. Todas las constantes de configuración que aquí se encuentren quedan configuradas a partir de aquí.
    • en $HOME se busca el archivo .mambupy.rc, para las configuraciones propias de cada usuario. Si alguna constante de configuración se encuentra aquí, su valor prevalece sobre las anteriores.
    • si se proporcionó el argumento en la línea de comandos --mambupy_rcfile con un path a un archivo de configuración específico, se usa este archivo. Igual que antes, las constantes de configuración aquí encontradas prevalecen sobre las anteriores.
    • si existe una variable de entorno en particular, se toma su valor para configurar cierta constante de configuración, prevaleciendo sobre la misma, si se encontraba en alguna de las opciones anteriores.
    • los argumentos en línea de comandos, con los que se hubiera invocado el programa que utilice MambuPy, tienen la máxima prioridad y prevalecen sobre cualquier otra anterior.
  • Los archivos de configuración tienen el formato de los archivos INI, tan comunes en Windows. Básicamente se tienen secciones cuyos nombres se encierran entre corchetes, y cada nombre de constante de configuración va seguido de un signo de igual y del valor que le corresponda.
  • Por lo tanto, mambuconfig usa ConfigParser para leer los archivos de configuración, que acepta el formato INI de forma nativa.
  • Las variables de entorno deben llamarse de la siguiente manera:
    • MAMBUPY_UPPERCASEOPTION, es decir el prefijo MAMBUPY_ seguido del nombre de la constante de configuración, todo en mayúsculas.
  • Los argumentos en línea de comandos deben llamarse de la siguiente manera:
    • mambupy_lowercaseoption, es decir el prefijo mambupy_ seguido del nombre de la constante de configuración, todo en minúsculas.
  • Por último, las configuraciones que soporta MambuPy actualmente (v1.3.6) son:
[API]
apiurl=url_to_mambu_domain
apiuser=API_user
apipwd=API_password
[DB]
dbname=Database_name
dbuser=Database_user
dbpwd=Database_password
dbhost=Database_host
dbport=Database_port
dbeng=Database_engine

 

Configurar bien es más que sólo dar opciones a un usuario. Recuérdalo: primero ubica qué quieres configurar (y qué no deberías de configurar), y luego define cómo se hará.

Etiquetas