El infierno de las dependencias es un término coloquial para la frustración de algunos usuarios de software que han instalado paquetes de software que tienen dependencias de versiones específicas de otros paquetes de software. [ 1 ]
El problema de dependencia surge cuando varios paquetes dependen de los mismos paquetes o bibliotecas compartidas , pero dependen de versiones diferentes e incompatibles de dichos paquetes. Si el paquete o la biblioteca compartida solo se puede instalar en una única versión, el usuario podría necesitar solucionar el problema obteniendo versiones más recientes o más antiguas de los paquetes dependientes. Esto, a su vez, podría romper otras dependencias y trasladar el problema a otro conjunto de paquetes.
Problemas
El infierno de la dependencia adopta varias formas:
Muchas dependencias
- Una aplicación depende de muchas bibliotecas , lo que requiere descargas largas, grandes cantidades de espacio en disco y ser muy portable (todas las bibliotecas ya están adaptadas, lo que permite que la propia aplicación se adapte fácilmente). También puede ser difícil localizar todas las dependencias, lo que se puede solucionar con un repositorio (véase más abajo). Esto es en parte inevitable; una aplicación creada en una plataforma informática determinada (como Java ) requiere que dicha plataforma esté instalada, pero otras aplicaciones no la requieren. Esto supone un problema particular si una aplicación utiliza una pequeña parte de una biblioteca grande (lo que se puede solucionar mediante la refactorización del código ) o si una aplicación sencilla depende de muchas bibliotecas. [ 2 ]
Largas cadenas de dependencias
- Si la aplicación depende de liba , que depende de libb , ..., que depende de libz . Esto es distinto de "muchas dependencias" si las dependencias deben resolverse manualmente, por ejemplo, al intentar instalar la aplicación , se le pide al usuario que instale primero liba y al intentar instalar liba , se le pide al usuario que instale libb , y así sucesivamente. Sin embargo, a veces, durante esta larga cadena de dependencias, surgen conflictos cuando se requieren dos versiones diferentes del mismo paquete [ 3 ] (ver dependencias conflictivas más abajo). Estas largas cadenas de dependencias se pueden resolver con un gestor de paquetes que resuelva todas las dependencias automáticamente. Además de ser una molestia (resolver todas las dependencias manualmente), la resolución manual puede enmascarar ciclos de dependencia o conflictos.
Dependencias conflictivas
- Resolver las dependencias de un software puede romper la compatibilidad de otro de forma similar al juego de golpear al topo . Si app1 depende de libfoo 1.2 y app2 de libfoo 2.0, y no se pueden instalar simultáneamente diferentes versiones de libfoo , entonces app1 y app2 no se pueden usar (o instalar, si el instalador verifica las dependencias) simultáneamente. Cuando es posible, esto se soluciona permitiendo la instalación simultánea de las diferentes dependencias. Alternativamente, la dependencia existente, junto con todo el software que depende de ella, debe desinstalarse para instalar la nueva dependencia. Un problema en los sistemas Linux al instalar paquetes de un distribuidor diferente es que la larga cadena de dependencias resultante puede llevar a una versión conflictiva de la biblioteca estándar de C (por ejemplo, la biblioteca GNU C ), de la que dependen miles de paquetes. Si esto sucede, se le pedirá al usuario que desinstale todos esos paquetes.
dependencias circulares
- Si la aplicación A depende de una versión específica de la aplicación B y no puede ejecutarse sin ella , y la aplicación B, a su vez, depende de una versión específica de la aplicación A y no puede ejecutarse sin ella , entonces actualizar cualquiera de las aplicaciones provocará fallos en las demás. Este esquema puede ser más complejo en las ramificaciones. Su impacto puede ser considerable si afecta a sistemas centrales o al propio software de actualización: un gestor de paquetes ( A ), que requiere una biblioteca de tiempo de ejecución específica ( B ) para funcionar, puede fallar ( A ) durante el proceso de actualización de dicha biblioteca ( B ) a la siguiente versión. Debido a una versión incorrecta de la biblioteca ( B ), el gestor de paquetes ( A ) queda inoperativo, por lo que no es posible revertir ni degradar la biblioteca ( B ). La solución habitual consiste en descargar e implementar ambas aplicaciones, a veces desde un entorno temporal.
dependencias del gestor de paquetes
- Es posible [ 4 ] que el infierno de las dependencias resulte de la instalación de un paquete preparado a través de un gestor de paquetes (por ejemplo, APT ), pero esto es improbable ya que los principales gestores de paquetes han madurado y los repositorios oficiales se mantienen adecuadamente. Este es el caso de las versiones actuales de Debian y sus principales derivados, como Ubuntu . Sin embargo, el infierno de las dependencias puede resultar de la instalación de un paquete directamente a través de un instalador de paquetes (por ejemplo, RPM Package Manager (RPM) o dpkg ).
dependencia del diamante
- Cuando la biblioteca A depende de las bibliotecas B y C , ambas dependen de la biblioteca D , pero B requiere la versión D.1 y C requiere la versión D.2 . La compilación falla porque solo puede existir una versión de D en el ejecutable final.
- Los gestores de paquetes como yum [ 5 ] son propensos a tener conflictos entre los paquetes de sus repositorios, lo que provoca un infierno de dependencias en distribuciones de Linux como CentOS y Red Hat Enterprise Linux .
Soluciones
Eliminando dependencias
- Muchas bibliotecas de software están escritas de forma generosa, con el objetivo de satisfacer las necesidades de la mayoría de los usuarios, pero a veces solo se requiere una pequeña parte de las funciones en el código principal. Al examinar el código fuente, la funcionalidad se puede reescribir de una manera mucho más compacta (respetando la licencia). En general, esto puede reducir significativamente el código de la aplicación, disminuir los costos de mantenimiento posteriores y mejorar las habilidades de programación de los desarrolladores.
Numeración de versiones
- Una solución muy común a este problema es tener un sistema de numeración estandarizado, donde el software usa un número específico para cada versión (también conocida como versión principal ) y también un subnúmero para cada revisión (también conocida como versión secundaria ), por ejemplo: 10.1 o 5.7 . La versión principal solo cambia cuando los programas que usaban esa versión dejan de ser compatibles. La versión secundaria puede cambiar incluso con una simple revisión que no impide que otro software funcione con ella. En casos como este, los paquetes de software pueden simplemente solicitar un componente que tenga una versión principal particular y cualquier versión secundaria (mayor o igual que una versión secundaria particular). De esta manera, seguirán funcionando y las dependencias se resolverán correctamente, incluso si la versión secundaria cambia. El versionado semántico (también conocido como "SemVer" [ 6 ] ) es un ejemplo de un esfuerzo por generar una especificación técnica que emplea números con formato específico para crear un esquema de versionado de software.
Versiones privadas por aplicación
- La protección de archivos de Windows , introducida en Windows 2000 , impedía que las aplicaciones sobrescribieran las bibliotecas de vínculos dinámicos (DLL) del sistema. En su lugar, se animaba a los desarrolladores a utilizar DLL privadas, que eran duplicados de las DLL del sistema almacenadas en la carpeta del programa. Esto requiere que las dependencias personalizadas se incluyan en el programa, evitando así el problema de las dependencias complejas. [ 7 ]
- PC-BSD, hasta la versión 8.2 inclusive, un predecesor de TrueOS (un sistema operativo basado en FreeBSD ), coloca los paquetes y las dependencias en directorios autocontenidos en /Programs , lo que evita fallos si se actualizan o modifican las bibliotecas del sistema. Utiliza su propio instalador de botón (PBI) para la gestión de paquetes. [ 8 ]
Instalación paralela de múltiples versiones
- La solución de numeración de versiones se puede mejorar elevando la numeración de versiones a una función compatible con el sistema operativo. Esto permite que una aplicación solicite un módulo o biblioteca mediante un nombre único y restricciones de número de versión, transfiriendo así la responsabilidad de gestionar las versiones de la biblioteca o módulo de las aplicaciones al sistema operativo. Un módulo compartido se puede entonces ubicar en un repositorio central sin riesgo de dañar las aplicaciones que dependen de versiones anteriores o posteriores del módulo. Cada versión tiene su propia entrada, junto con las demás versiones del mismo módulo.
- Esta solución se utiliza en los sistemas operativos Microsoft Windows desde Windows Vista, donde la caché global de ensamblados es una implementación de un registro central con servicios asociados e integrada con el sistema de instalación/administrador de paquetes. Gentoo Linux resuelve este problema con un concepto llamado ranurado, que permite instalar múltiples versiones de bibliotecas compartidas. [ 9 ]
Gestión inteligente de paquetes
- Algunos gestores de paquetes pueden realizar actualizaciones inteligentes, en las que los componentes de software interdependientes se actualizan al mismo tiempo, resolviendo así también el problema principal de incompatibilidad numérica.
- Muchas distribuciones de Linux actuales también han implementado sistemas de gestión de paquetes basados en repositorios para intentar resolver el problema de las dependencias. Estos sistemas son una capa que se superpone al gestor de paquetes RPM (RPM), dpkg u otros sistemas de empaquetado, diseñados para resolver automáticamente las dependencias mediante la búsqueda en uno o más repositorios de software predefinidos . Algunos ejemplos de estos sistemas son la herramienta de empaquetado avanzado ( APT ), Yum , Urpmi , ZYpp , Portage , Pacman y otros. Normalmente, los repositorios de software son sitios o sitios web de protocolo de transferencia de archivos (FTP), directorios en el ordenador local o compartidos a través de una red o, con mucha menos frecuencia, directorios en medios extraíbles como CD o DVD. Esto elimina el infierno de las dependencias para el software empaquetado en esos repositorios, que suelen ser mantenidos por el proveedor de la distribución de Linux y replicados en todo el mundo. Aunque estos repositorios suelen ser enormes, no es posible tener en ellos todo el software, por lo que el infierno de las dependencias aún puede ocurrir. En todos los casos, los responsables del mantenimiento de los repositorios siguen enfrentándose al infierno de las dependencias. [ 4 ]
Opciones de instalación
- Debido a que los distintos programas tienen diferentes dependencias, es posible caer en un círculo vicioso de requisitos de dependencia , o en un árbol de requisitos en constante expansión, ya que cada nuevo paquete exige la instalación de varios más. Sistemas como la Herramienta de Empaquetado Avanzado ( APT ) de Debian pueden resolver este problema presentando al usuario diversas soluciones y permitiéndole aceptarlas o rechazarlas según sus preferencias.
Fácil adaptabilidad en la programación
- Si el software de aplicación se diseña de forma que sus programadores puedan adaptar fácilmente la interfaz de usuario (que interactúa con el sistema operativo, el gestor de ventanas o el entorno de escritorio) a estándares nuevos o cambiantes, solo tendrían que estar atentos a las notificaciones de los creadores del entorno o de los diseñadores de la biblioteca de componentes y actualizar rápidamente su software para los usuarios, todo ello con un mínimo esfuerzo y sin necesidad de rediseños costosos y que consuman mucho tiempo. Este método incentivaría a los programadores a presionar a sus colaboradores para que mantengan un proceso de notificación razonable que no resulte engorroso para nadie.
Requisito estricto de compatibilidad en el desarrollo y mantenimiento del código.
- Si las aplicaciones y bibliotecas se desarrollan y mantienen con compatibilidad retroactiva garantizada, cualquier aplicación o biblioteca puede reemplazarse por una versión más reciente en cualquier momento sin que se produzcan fallos. Si bien esto no elimina la multitud de dependencias, sí facilita enormemente el trabajo de los gestores de paquetes o instaladores.
Dispositivos de software
- Otro enfoque para evitar problemas de dependencias es implementar las aplicaciones como un dispositivo de software . Un dispositivo de software encapsula las dependencias en una unidad autocontenida preintegrada, de modo que los usuarios ya no tienen que preocuparse por resolverlas. En cambio, la responsabilidad recae en los desarrolladores del dispositivo. Los contenedores y sus imágenes (como las que ofrecen Docker y Docker Hub) pueden considerarse una implementación de dispositivos de software.
Aplicaciones portátiles
- Una aplicación (o una versión de una aplicación convencional existente) que es completamente autónoma y no requiere que nada esté instalado previamente. Está codificada para incluir todos los componentes necesarios o está diseñada para mantener todos los archivos necesarios dentro de su propio directorio, y no creará problemas de dependencias. Estas aplicaciones suelen poder ejecutarse independientemente del sistema al que están conectadas. Las aplicaciones en RISC OS y ROX Desktop para Linux utilizan directorios de aplicaciones , que funcionan de manera muy similar: los programas y sus dependencias están autónomos en sus propios directorios (carpetas). [ 10 ]
- Este método de distribución también ha demostrado ser útil al portar aplicaciones diseñadas para plataformas tipo Unix a Windows, siendo el inconveniente más notable la necesidad de instalar varias copias de las mismas bibliotecas compartidas . Por ejemplo, los instaladores de Windows para gedit , GIMP y HexChat incluyen copias idénticas del kit de herramientas GTK , que estos programas utilizan para renderizar widgets. Por otro lado, si cada aplicación requiere versiones diferentes de GTK, este comportamiento es el correcto y evita con éxito el problema de las dependencias.
Específico de la plataforma
En determinadas plataformas informáticas , el problema de las dependencias suele recibir un nombre específico local, generalmente el nombre de los componentes.
- El infierno de las DLL : una forma de infierno de dependencias que ocurre en Microsoft Windows de 16 bits .
- Conflicto de extensiones : una forma de infierno de dependencias que ocurre en el Mac OS clásico .
- El infierno de los JAR : una forma de infierno de dependencias que se producía en el entorno de ejecución de Java antes de que herramientas de compilación como Apache Maven resolvieran este problema en 2004.
- El infierno de RPM: una forma de infierno de dependencias que ocurre en la distribución Red Hat de Linux y otras distribuciones que utilizan RPM como gestor de paquetes. [ 11 ]
Véase también
- Catch-22 : una situación en la que la solución de un problema depende de circunstancias contradictorias, llamada así por un concepto descrito en una novela de 1961.
- Gestión de la configuración : técnicas y herramientas para gestionar las versiones de software.
- Acoplamiento : formas de dependencia entre artefactos de software
- Eliminación dinámica de código muerto
- gestor de paquetes
- PBI
- Dispositivo de software
- Biblioteca estática
- Ataque a la cadena de suministro
- Nix (gestor de paquetes)
- incidente de npm left-pad
Referencias
- ↑ Michael Jang (2006). Molestias de Linux para geeks . O'Reilly Media, Inc. pág . 325. ISBN 9780596552244. Consultado el 16 de febrero de 2012 .
- ↑ Donald, James (25 de enero de 2003). "Mejora de la portabilidad de las bibliotecas compartidas" (PDF) . Universidad de Princeton . Archivado del original (PDF) el 26 de septiembre de 2007. Consultado el 9 de abril de 2010 .
- ↑ Stevens, Al (1 de mayo de 2001). "Es un buen trabajo cuando se puede encontrar; el carrusel de la dependencia" . J-DDJ . 26 (5): 121–124 . ISSN 1044-789X . Archivado del original el 11 de agosto de 2011. Recuperado el 10 de abril de 2010 a través de drdobbs.com/blog.
- 1 2 Pjotr Prins; Jeeva Suresh y Eelco Dolstra (22-12-2008). "Nix soluciona el infierno de las dependencias en todas las distribuciones de Linux" . linux.com . Archivado del original el 08-07-2015 . Recuperado el 22-05-2013 .
Todos los gestores de paquetes populares, incluidos APT, RPM y FreeBSD Ports Collection, sufren el problema de las actualizaciones destructivas. Cuando realizas una actualización, ya sea para una sola aplicación o para todo tu sistema operativo, el gestor de paquetes sobrescribirá los archivos que se encuentran actualmente en tu sistema con versiones más recientes. Mientras los paquetes sean siempre perfectamente retrocompatibles, esto no es un problema, pero en el mundo real, los paquetes no son nada perfectamente retrocompatibles. Supongamos que actualizas Firefox y tu gestor de paquetes decide que también necesitas una versión más reciente de GTK. Si el nuevo GTK no es del todo retrocompatible, entonces otras aplicaciones en tu sistema podrían dejar de funcionar repentinamente. En el mundo de Windows, un problema similar se conoce como el infierno de las DLL, pero el infierno de las dependencias es un problema igual de grave en el mundo de Unix, si no mayor, porque los programas de Unix tienden a tener muchas dependencias externas.
- ↑ "Yum Dependency Hell" . Archivado del original el 19/12/2016 . Consultado el 28/12/2015 .
- ↑ "Sitio web del proyecto: semver.org" .
- ↑ Anderson, Rick (11 de enero de 2000). "El fin del infierno de las DLL" . Microsoft.com . Archivado del original el 5 de junio de 2001. Consultado el 7 de julio de 2010 .
- ↑ "Directorio pbi" . Archivado del original el 27 de marzo de 2013.
- ↑ "Slotting" . gentoo.org . Consultado el 10 de marzo de 2025 .
- ↑ "Directorios de aplicaciones" . Consultado el 7 de septiembre de 2013 .
- ↑ Weinstein, Paul (11 de septiembre de 2003). "¿Es Linux molesto?" . linuxdevcenter.com . Consultado el 10 de abril de 2010 .
- Sistemas de gestión de paquetes
- Sistemas de control de versiones
- Errores informáticos
- Folclore de la ingeniería de software