Articulo de referencia

Problema de interfaz binaria frágil

El problema de la interfaz binaria frágil o FBI es una deficiencia de ciertos compiladores de lenguajes de programación orientados a objetos , en los que los cambios internos en...

El problema de la interfaz binaria frágil o FBI es una deficiencia de ciertos compiladores de lenguajes de programación orientados a objetos , en los que los cambios internos en una biblioteca de clases subyacente pueden provocar que las bibliotecas o programas descendientes dejen de funcionar. Es un ejemplo de fragilidad del software .

Este problema se denomina más a menudo problema de la clase base frágil o FBC ; sin embargo, ese término tiene un sentido más amplio.

Causa

El problema se produce debido a un "atajo" utilizado con los compiladores para muchos lenguajes orientados a objetos (OO) comunes, una característica de diseño que se mantuvo cuando los lenguajes OO evolucionaron a partir de lenguajes de programación estructurados no OO anteriores como C y Pascal .

En estos lenguajes no existían objetos en el sentido moderno, pero sí una construcción similar conocida como registro (o "estructura" en C) que contenía una variedad de información relacionada en una pieza de memoria. Se accedía a las partes dentro de un registro en particular haciendo un seguimiento de la ubicación inicial del registro y conociendo el desplazamiento desde ese punto de inicio hasta la parte en cuestión. Por ejemplo, un registro de "persona" podría tener un nombre, un apellido y la inicial del segundo nombre, para acceder a la inicial que escribe el programador thisPerson.middleInitialy que el compilador convierte en algo como a = location(thisPerson) + offset(middleInitial). Las CPU modernas suelen incluir instrucciones para este tipo común de acceso.

Cuando se empezaron a desarrollar los compiladores de lenguajes orientados a objetos, se utilizaba gran parte de la tecnología de compilación existente y los objetos se creaban sobre el concepto de registro. En estos lenguajes, se hacía referencia a los objetos por su punto de partida y se accedía a sus datos públicos, conocidos como "campos", a través del desplazamiento conocido. En efecto, el único cambio fue añadir otro campo al registro, que se configura para que apunte a una tabla de métodos virtuales inmutables para cada clase, de modo que el registro describa tanto sus datos como sus métodos (funciones). Cuando se compila, los desplazamientos se utilizan para acceder tanto a los datos como al código (a través de la tabla de métodos virtuales).

Síntomas

Esto genera un problema en programas más grandes cuando se construyen a partir de bibliotecas . Si el autor de la biblioteca cambia el tamaño o el diseño de los campos públicos dentro del objeto, las compensaciones ya no son válidas y el programa ya no funcionará. Este es el problema del FBI.

Aunque se puede esperar que los cambios en la implementación causen problemas, lo insidioso de FBI es que nada cambió realmente , solo el diseño del objeto que está oculto en una biblioteca compilada. Uno podría esperar que si uno cambia doSomethingeso doSomethingElsepodría causar un problema, pero en este caso uno puede causar problemas sin cambiar doSomething, puede causarlos tan fácilmente como mover líneas de código fuente para mayor claridad. Peor aún, el programador tiene poco o ningún control sobre el diseño resultante generado por el compilador, lo que hace que este problema esté casi completamente oculto a la vista.

En programas o bibliotecas orientados a objetos complejos , las clases de nivel más alto pueden heredar de decenas de clases. Cada una de esas clases base también puede ser heredada por cientos de otras clases. Estas clases base son frágiles porque un pequeño cambio en una de ellas puede causar problemas para cualquier clase que herede de ella, ya sea directamente o de otra clase que lo haga. Esto puede hacer que la biblioteca se derrumbe como un castillo de naipes , ya que muchas clases se dañan por un cambio en una clase base. El problema puede no notarse cuando se escriben las modificaciones si el árbol de herencia es complejo. De hecho, el desarrollador que modifica la clase base generalmente no sabe qué clases, desarrolladas por otros, la están utilizando.

Soluciones

Idiomas

Una solución al problema de la interfaz binaria frágil es escribir un lenguaje que sepa que el problema existe y que no permita que suceda en primer lugar. La mayoría de los lenguajes OO escritos a medida, a diferencia de los que evolucionaron a partir de lenguajes anteriores, construyen todas sus tablas de desplazamiento en el momento de la carga. Los cambios en el diseño de la biblioteca se "notarán" en ese momento. Otros lenguajes OO, como Self , construyen todo en tiempo de ejecución copiando y modificando los objetos que se encuentran en las bibliotecas y, por lo tanto, no tienen realmente una clase base que pueda ser frágil. Algunos lenguajes, como Java , tienen una amplia documentación sobre qué cambios son seguros para realizar sin causar problemas de FBI.

Otra solución es escribir un archivo intermedio que incluya los desplazamientos y otra información de la etapa de compilación, conocida como metadatos. El enlazador utiliza luego esta información para corregirse a sí mismo cuando se carga la biblioteca en una aplicación. Plataformas como .NET hacen esto.

Sin embargo, el mercado ha seleccionado lenguajes de programación como C++ que son efectivamente "dependientes de la posición" y por lo tanto presentan FBI. En estos casos todavía hay varias soluciones al problema. Una de ellas es poner la carga sobre el autor de la biblioteca haciendo que inserte una serie de objetos "de reserva" en caso de que necesite agregar funcionalidad adicional en el futuro (esto se puede ver en las estructuras utilizadas en la biblioteca DirectX ). Esta solución funciona bien hasta que se agotan estos objetos ficticios y no se desea agregar demasiados porque ocupan memoria.

Objective-C 2.0 proporciona variables de instancia no frágiles al tener un nivel adicional de indirección para el acceso a las variables de instancia.

Otra solución parcial es utilizar el patrón Bridge , a veces conocido como " Pimpl " ("Pointer to implementation"). El framework Qt es un ejemplo de este tipo de implementación. Cada clase define solo un miembro de datos, que es un puntero a la estructura que contiene los datos de implementación. Es poco probable que el tamaño del puntero en sí cambie (para una plataforma determinada), por lo que cambiar los datos de implementación no afecta el tamaño de la estructura pública. Sin embargo, esto no evita otros cambios importantes, como la introducción de métodos virtuales en una clase que no tiene ninguno o el cambio del gráfico de herencia.

Enlazadores

Otra solución requiere un enlazador más inteligente. En la versión original de Objective-C , el formato de la biblioteca permitía múltiples versiones de una biblioteca e incluía alguna funcionalidad para seleccionar la biblioteca adecuada cuando se la llamaba. Sin embargo, esto no siempre era necesario porque los desplazamientos solo eran necesarios para los campos, ya que los desplazamientos de los métodos se recopilaban en tiempo de ejecución y no podían causar FBI. Dado que los métodos tienden a cambiar con más frecuencia que los campos, ObjC tuvo pocos problemas de FBI en primer lugar, y los que tuvo se pudieron corregir con el sistema de control de versiones. Objective-C 2.0 agregó un "tiempo de ejecución moderno" que resolvió el problema de FBI para los campos también. Además, el lenguaje TOM usa desplazamientos recopilados en tiempo de ejecución para todo, lo que hace que FBI sea imposible.

Otra solución es utilizar bibliotecas estáticas en lugar de dinámicas siempre que sea posible, ya que la biblioteca no se puede modificar sin volver a compilar la aplicación y actualizar los desplazamientos que utiliza. Sin embargo, las bibliotecas estáticas tienen sus propios problemas graves, como un binario más grande y la incapacidad de utilizar versiones más nuevas de la biblioteca "automáticamente" a medida que se introducen.

Arquitectura

En estos lenguajes el problema se reduce al imponer la herencia única (ya que esto reduce la complejidad del árbol de herencia) y al usar interfaces en lugar de clases base con funciones virtuales , ya que las interfaces en sí mismas no contienen código, solo una garantía de que cada firma de método que declara la interfaz será compatible con cada objeto que implemente la interfaz.

Método de distribución

Todo el problema se derrumba si el código fuente de las bibliotecas está disponible. En ese caso, una simple recompilación resolverá el problema.

Véase también

Obtenido de "https://es.wikipedia.org/w/index.php?title=Problema_de_interfaz_binaria_frágil&oldid=873152636"