| Full Text | Modularización: Arquitecturas de paquetes al rescate
Convirtiendo a la hidra en nuestra aliada
En el número 27 de Software Gurú, Agustín Ramos presentó un
artículo acerca de estrategias para lograr una modularización efectiva
en Java. Varios de los puntos de su artículo me llevaron a dedicar la
presente columna a explicar a qué llamamos una distribución
de Linux, y cuál es su relación –y la solución que ofrece– a los
problemas derivados de la complejidad derivada de la modularización,
que bien describió Agustín.
Como deben ya saberlo, a diferencia de otros sistemas operativos,
el entorno operativo completo al que normalmente nos referimos como
Linux no es desarrollado por un sólo grupo, ni sigue un
roadmap, criterios o visión en común. Mucho se ha argumentado
acerca de las características que diferencían a los proyectos
desarrollados desde planteamientos libres de aquellos desarrollados
siguiendo metodologías tradicionales — No abordaré dicha discusión en
este momento. Sin embargo, no quiero dejar de aprovechar la
oportunidad de tener un artículo escrito por un colega en esta revista
para ilustrar cómo abordamos la relación entre proyectos
independientes –que logran una complejidad de miras mucho mayor que
cualquier instancia de conjuntos de módulos desarrollados en
casa– en el Software Libre, por qué enfatizamos tanto en lo
prevalente que resulta dicha modularización, y cómo nos enfrentamos a
su inherente complejidad.
Los sistemas basados en Linux son estructurados, pues, en
distribuciones. Una distribución es un conjunto de programas
–típicamente del órden de miles– que, entre todos, presentan la
funcionalidad que un usuario espera ya no sólo de un sistema operativo
sino que de todo un entorno operativo integrado. Además, se
encargan de gestionar las relaciones de dependencia entre dichos
programas, y resolver dichas dependencias, para facilitar al usuario
la instalación, remoción y actualización de software.
Una instalación mínima de cualquier distribución de Linux no tiene
menos de un par de centenares de paquetes individuales. El
núcleo Linux, por sí mismo, no representa más que la interfaz más
básica para presentar una abstracción del hardware ante los programas
que corren sobre él. Formalmente, al mencionar Linux ni
siquiera nos referimos a la interfaz de línea de comandos (misma que
generalmente es provista por los paquetes bash, dash
o sash, dependiendo de las necesidades del
administrador). Son en realidad contados los paquetes que no dependen
más que de paquetes esenciales. Toda distribución define un
pequeño conjunto (decenas) de programas que es fundamental tener
instalados como base para cualquier otro, conjunto mínimo que asumimos
que siempre estará ahí para asegurarnos la funcionalidad mínima.
Si bien las primeras distribuciones tuvieron por objetivo facilitar
la instalación de un sistema basado en Linux a usuarios con menor
involucramiento técnico, y fueron instrumentales en la primer ola
expansiva de usuarios que fuimos adoptando Linux hacia mediados de los
1990, han trascendido ya a éste rol para dar respuesta al infierno
de dependencias al que se refiere en su texto Agustín Ramos:
Hacia fines de los 1990, aproximadamente cuando todas las
distribuciones comenzaban a contar en miles los paquetes
independientes que ofrecían, comenzó a hacerse obvio que no bastaba
con que cada paquete indicara de qué otros paquetes dependía
(incluyendo, claro está, la información de versiones pertinente), sino
que era necesario contar con una arquitectura de paquetes: Un
esquema orientado a depósitos y no a paquetes individuales,
que se encargara de resolver las dependencias cada que el
administrador instalara o eliminara un paquete. La primera
arquitectura fue introducida por la distribución Debian, bajo
el nombre de apt: A Package Tool. Es definitivamente gracias
a apt que, al día de hoy, la versión de desarrollo de Debian cuenta
con 15640 paquetes fuente independientes, que resultan en 27886
paquetes binarios, cubriendo prácticamente todas las áreas de
necesidad en cómputo, tanto a nivel de aplicaciones como de
bibliotecas.
A diferencia de otras arquitecturas previas, como
los ports de los Unixes BSD, Apt está además construido
basado en el manejo de depósitos múltiples. Esto significa
que, además de servirme para instalar los paquetes oficiales de la
distribución, nos permite definir depósitos adicionales con el
software que desarrollemos localmente, así como de paquetes
adicionales que preparemos localmente para uso en nuestra
organización.
Con esto como introducción, veamos cómo ésto se aplica al texto de
Agustín. Por razones de espacio, me enfoco a cómo éste esquema reduce
fuertemente los efectos negativos de la modularización, permitiendo a
los desarrolladores crear software más robusto y temer menos a esta
tan dificil de conciliar fuente de dolores de cabeza.
- Demasiadas dependencias
- El argumento principal mencionado en el texto al que hago
referencia en contra de tener demasiadas dependencias es la
posterior dificultad de instalación de nuestros sistemas. Sin
embargo, al crear paquetes con la información de las dependencias,
convertimos el fastidioso proceso de instalación (y todo el tiempo
que requiere documentarlo) en una sóla instrucción al
sistema.
- Dependencias cíclicas
- Coordinar el trabajo de cientos de voluntarios en todo el mundo,
sin más factores de cohesión que su voluntad por crear un sistema
de calidad trae como resultado natural el que parte importante de
sus esfuerzos estén encaminados a la creación de documentos de
políticas comprehensivos — y a que su comunidad de
desarrolladores comprenda la importancia de dichos
documentos.
Claro está, si la unidad atómica de trabajo en una distribución
es el paquete, problemas tan claros como las dependencias
cíclicas fueron de los primeros puntos en ser prohibidos por
política. Sin embargo, conforme la complejidad de cada uno de los
paquetes aumenta, se vuelve posible que aparezcan dependencias
cíclicas de indirectas. Para evitar problemas como este, y otros
destinados del control de calidad en sistemas complejos, se hacen
revisiones periódicas de todos los procesos imaginables.
En este aspecto, si bien no hay balas de plata para evitar las
dependencias cíclicas, contamos con una comunidad de
desarrolladores verificando que estos problemas se mantengan al
mínimo. No estamos sólos en el manejo de nuestros proyectos.
- Largas cadenas de dependencias
- Este fue precisamente el punto que motivó al desarrollo de las
arquitecturas de paquetes. Podemos confiar en que la arquitectura
que elijamos, empleando los depósitos del sistema y de nuestra
organización, sepan resolver este punto sin que represente
problemática alguna. Además, no tenemos por qué limitarnos al uso
de este esquema para las dependencias de los componentes externos
que empleemos. Si dentro de nuestra organización nos acostumbramos
a empaquetar nuestro código en componentes, la reutilización de
código que podamos hacer será muchísimo más simple y más
natural.
- Dependencias en conflicto
- Nuevamente, aquí acudimos a la sabiduría de las masas, a la
fuerza de la multitud. Una distribución basada en Linux no es
sólo un conjunto de programas disponibles a través de un mismo
depósito — La mayor parte del trabajo de sus creadores es
asegurarse que todos los componentes sean mutuamente compatibles,
y asegurar a los usuarios un producto de calidad, con todas las
actualizaciones necesarias para asegurar su seguridad (cuidando
no compormeter su estabilidad) durante su ciclo de vida.
Este puede ser un punto fundamental al elegir qué distribución
vamos a usasr para determinado proyecto: Hay distribuciones
principalmente orientadas al perfil de usuario de escritorio, para
el cual es fundamental tener siempre soporte completo para el
último hardware, aceleración gráfica compelta y demás
bondades. Sin embargo, para basar nuestros desarrollos
empresariales, típicamente preferiremos las distribuciones
con ciclos de vida más largos, con un mayor soporte a largo plazo.
Como pueden ver, manejar una arquitectura de paquetes simplifica
algunas de las tareas más complicadas (y más ingratas) del
desarrollo de software, el manejo de toda la talacha creada
por los componentes que, a fin de cuentas, incluimos
para ahorrarnos trabajo.
Cuando veo los instaladores típicos, que crean enormes amasijos
(típicamente en forma de enormes instaladores .msi o
archivos .jar que incluyen copia de todas las
dependencias para evitar estos problemas), no exagero: Me dan ganas
de llorar. Porque además, al tener varias copias de una misma
biblioteca en el sistema, tengo la certeza de que en caso de
aparecer algún defecto en alguna de ellas, habrá componentes de mi
sistema que reciban la corrección en cuestión — pero habrá otros que
no. Acostumbrarse al manejo de dependencias externas nos reduce la
tentación de acudir al tan temido ligado estático, reduce el peso de
nuestras imágenes de instalación (y de nuestros sistemas ya
instalados), y ayuda fuertemente a mantener un mayor control de
calidad en nuestros procesos como un todo.
Mucha gente evita aprovechar la modularización como medida
preventiva para no perder la razón resolviendo dependencias y bugs
creados por compatibilidad incompleta entre versiones. Sin embargo,
dejar de usar buen software, ya existente y probado por terceros,
sólo por no contar con las herramientas de seguimiento correctas es
un triste error en el que debemos evitar caer. La hidra de la
modularización a la que se refiere Agustín puede ser un mounstro
mortal, pero si aprendemos a hablar con ella puede ser nuestro mayor
aliado. Porque si dos cabezas piensan mejor que una, ¿qué decir de
decenas de cabezas? |
Post new comment