09 Jul
Capítulo 17 ■ Ingeniería de software basada en componentes 453
Como se explicó en el capítulo 16, numerosos y nuevos sistemas empresariales se desarrollan//ahora al configurar sistemas comerciales COTS. Sin embargo, cuando una compañía//no puede usar un sistema COTS porque no cubre sus requerimientos, el software//que se requiere debe desarrollarse especialmente. Para el software personalizado, la ingeniería//de software basada en componentes es una forma efectiva orientada a la reutilización//para desarrollar nuevos sistemas empresariales.//La ingeniería de software basada en componentes (CBSE, por las siglas de Component-//Based Software Engineering) surgió a finales de la década de 1990 como un enfoque//al desarrollo de sistemas de software basado en la reutilización de componentes//de software. Su creación fue motivada por la frustración de los diseñadores al percatarse de//que el desarrollo orientado a objetos no conducía a una reutilización extensa, como se había//sugerido originalmente. Las clases de objetos individuales eran muy detalladas y específicas//y con frecuencia tenían que acotarse con una aplicación al momento de compilar. Para//usarlas, se debe tener conocimiento detallado de las clases, y por lo general esto significa//tener el código fuente del componente. Por consiguiente, era casi imposible vender o distribuir//objetos como componentes de reutilización individuales.//Los componentes son abstracciones de alto nivel en comparación con los objetos y se//definen mediante sus interfaces. Por lo general, son más grandes que los objetos individuales//y todos los detalles de implementación se ocultan a otros componentes. La CBSE es el//proceso de definir, implementar e integrar o componer los componentes independientes e//imprecisos en los sistemas. Se ha constituido en un importante enfoque de desarrollo de software//porque los sistemas de software son cada vez más amplios y complejos. Los clientes//demandan un software más confiable que se entregue e implemente más rápidamente. La//única forma de enfrentar la complejidad y entregar un mejor software con mayor rapidez es//reutilizar en lugar de implementar una vez más los componentes de software.//Los fundamentos de la ingeniería de software basada en componentes son://1. Componentes independientes que se especifican por completo mediante sus interfaces.//Debe existir una separación clara entre la interfaz del componente y su implementación.//Esto significa que la implementación de un componente puede sustituirse//por otra, sin cambiar otras partes del sistema.//2. Estándares de componentes que facilitan la integración de éstos. Tales estándares se//incrustan en un modelo de componentes. Definen, a un nivel mínimo, cómo deben//especificarse las interfaces de componentes y cómo se comunican estos últimos.//Algunos modelos van más allá y definen las interfaces que deben implementarse por//todos los componentes integrantes. Si los componentes se conforman a los estándares,//entonces su ejecución es independiente de su lenguaje de programación. Los componentes//escritos en diferentes lenguajes pueden integrarse en el mismo sistema.//3. Middleware que brinda soporte de software para integración de componentes. Para//hacer que componentes independientes distribuidos trabajen en conjunto, es necesario//soporte de middleware que maneje las comunicaciones de componentes. El//middleware para soporte de componentes maneja eficientemente los conflictos de//bajo nivel y permite enfocarse en problemas relacionados con la aplicación. Además,//el middleware para soporte de componentes puede brindar apoyo para la asignación//de recursos, la gestión de transacciones, la seguridad y concurrencia.//4. Un proceso de desarrollo que se engrana con la ingeniería de software basada en//componentes. Usted necesita un proceso de desarrollo que permita la evolución de//Capítulo 17 ■ Ingeniería de software basada en componentes 453//454 Capítulo 17 ■ Ingeniería de software basada en componentes//requerimientos, dependiendo de la funcionalidad de los componentes disponibles.//En la sección 17.2 se estudian los procesos de desarrollo CBSE.//El desarrollo basado en componentes implica una buena práctica de ingeniería de software.//Tiene sentido diseñar un sistema mediante componentes, incluso si usted debe desarrollarlos//en vez de reutilizarlos. En la base de la CBSE existen firmes principios de diseño//que apoyan la construcción de software comprensible y mantenible://1. Los componentes son independientes, de manera que sus ejecuciones no interfieren//entre sí. Se ocultan los detalles de la implementación. La implementación de componentes//puede cambiar sin afectar al resto del sistema.//2. Los componentes se comunican a través de interfaces bien definidas. Si dichas interfaces//se mantienen, es posible sustituir un componente por otro, lo que ofrece funcionalidad//adicional o mayor.//3. Las infraestructuras de componentes ofrecen varios servicios estándar que pueden//usarse en sistemas de aplicación. Esto reduce la cantidad de código nuevo que debe//desarrollarse.//La motivación inicial para la CBSE fue la necesidad de brindar apoyo tanto a la ingeniería//de software de reutilización como a la distribuida. Un componente se considera//como un elemento de un sistema de software al que se podría acceder, mediante un mecanismo//llamado procedimiento remoto, por parte de otros componentes que se ejecutan en//computadoras independientes. Cada sistema que reutiliza un componente debe incorporar//su propia copia de dicho componente. Esta idea de componente se extiende a la noción//de objetos distribuidos, como se define en modelos de sistemas distribuidos, tales como//la especificación CORBA (Pope, 1997). Para apoyar esta visión de componente, se han//desarrollado muchos y diferentes protocolos y estándares, como el Enterprise Java Beans//(EJB) de Sun, COM y .NET de Microsoft, y CCM de CORBA (Lau y Wang, 2007).//En la práctica, estos estándares múltiples obstaculizan la aceptación de CBSE. Era//imposible que componentes desarrollados mediante diferentes enfoques funcionaran juntos.//Los componentes diseñados para distintas plataformas, tales como .NET o J2EE,//no pueden interoperar. Más aún, los estándares y protocolos propuestos se consideraban//complejos y difíciles de entender. Esto también se presentaba como una barrera para su//adopción.//En respuesta a tales problemas, se desarrolló la noción de componente como un servicio,//y se propusieron estándares para apoyar la ingeniería de software orientada a servicios.//Problemas con CBSE//La CBSE es ahora un enfoque de mantenimiento a la ingeniería de software: es una buena forma de construir//sistemas. Sin embargo, cuando se usa como enfoque para la reutilización, los problemas se relacionan con//la fiabilidad y certificación de los componentes, los compromisos de requerimientos y la predicción de las//propiedades de los componentes, en especial al integrarse con otros.//http://www.SoftwareEngineering-9.com/Web/CBSE/problems.html//17.1 ■ Componentes y modelos de componentes 455//La diferencia más significativa entre un componente como servicio y la noción original de//componente es que los servicios son entidades independientes externas a un programa que//los usa. Cuando se construye un sistema orientado al servicio, se hace referencia al servicio//externo en vez de incluir en su sistema una copia de dicho servicio.//Por lo tanto, la ingeniería de software orientada al servicio, que se estudia en el capítulo//19, es un tipo de ingeniería de software basada en componentes. Utiliza una noción//más simple de componente que el propuesto originalmente en CBSE. Los estándares//impulsaron esto desde el comienzo. En situaciones en que no es práctica la reutilización//basada en COTS, la CBSE orientada al servicio se convierte en el enfoque dominante//para el desarrollo de sistemas empresariales.//17.1 Componentes y modelos de componentes//En la comunidad CBSE existe un acuerdo general de que un componente es una unidad//de software independiente que puede organizarse con otros componentes para crear un//sistema de software. Sin embargo, más allá de eso, hay quienes proponen definiciones//variables de un componente de software. Council y Heineman (2001) definen un componente//como://Un elemento de software que se conforma a un modelo de componentes estándar//y puede desplegarse y componerse independientemente sin modificación, de//acuerdo con un estándar de composición.//En esencia, esta definición se basa en estándares, de manera que una unidad de software//conformada a dichos estándares es un componente. No obstante, Szyperski (2002)//no menciona estándares en su definición de componente; en vez de ello, se enfoca en//características clave de los componentes://Un componente de software es una unidad de composición con interfaces especificadas//contractualmente y sólo con dependencias de contexto explícitas. Un componente//de software puede implementarse de manera independiente y está sujeto a//composición por terceras partes.//Ambas definiciones se basan en la noción de componente como elemento que se//incluye en un sistema, más que en un servicio al que hace referencia el sistema. Con todo,//también son compatibles con la idea de un servicio como un componente.//Szyperski establece además que un componente no tiene estado observable externo.//Esto significa que las copias de los componentes son indistinguibles. No obstante, algunos//modelos de componentes, tales como el modelo Enterprise Java Beans, permiten//componentes de estado, así que no corresponden a la definición de Szyperski. Aunque//los componentes sin estado son más simples de usar, existen algunos sistemas en que los//componentes de estado son más convenientes y reducen la complejidad del sistema.//Lo que tienen en común las definiciones anteriores es que concuerdan en que los//componentes son independientes, y los consideran la unidad fundamental de composición//en un sistema. La visión del autor es que puede obtenerse una mejor definición de//456 Capítulo 17 ■ Ingeniería de software basada en componentes//componente al combinar estas propuestas. La figura 17.1 muestra lo que el autor considera//como las características esenciales de un componente, como se usa en CBSE.//Una forma útil de pensar en un componente es como un proveedor de uno o más//servicios. Cuando un sistema necesita un servicio, llama a un componente que brinde//0programación que se usó para desarrollarlo. Por ejemplo, un componente en un sistema//de biblioteca puede ofrecer un servicio de búsqueda que permita a los usuarios examinar//diferentes catálogos de la biblioteca. Un componente que convierte de un formato gráfico//a otro (por ejemplo, TIFF a JPEG) ofrece un servicio de conversión de datos, etcétera.//Visualizar un componente como un proveedor de servicio pone de relieve dos características//críticas de un componente de reutilización://1. El componente es una entidad ejecutable independiente definida mediante sus interfaces.//Para usarlo no se necesita conocimiento alguno de su código fuente. Puede hacerse//referencia a él como un servicio externo o incluirse directamente en un programa.//2. Los servicios ofrecidos por un componente se ponen a disposición mediante una interfaz,//y todas las interacciones por dicha interfaz. La interfaz del componente se expresa//en términos de operaciones parametrizadas y nunca se expone su estado interno.//Característica del componente Descripción//Estandarizado Estandarización de componentes significa que un componente utilizado//durante un proceso CBSE debe ajustarse a un modelo de componentes//estándar. Este modelo puede definir interfaces de componentes,//metadatos de componentes, documentación, composición//e implementación.//Independiente Un componente debe ser independiente; debe ser factible componerlo//e implementarlo sin usar otros componentes específicos. En situaciones//en que el componente necesita brindar servicios externos, esto debería//plantearse claramente en una especificación de interfaz de “requiere”.//Componible Para que un componente sea componible, todas las interacciones//externas deben tener lugar mediante interfaces definidas públicamente.//Además, debe permitir acceso externo a información acerca de sí//mismo, así como a sus métodos y atributos.//Implementable Para que sea implementable, un componente debe estar autocontenido.//Debe ser capaz de ejecutarse como entidad independiente en//una plataforma de componente que permita una implementación//del modelo de componentes. Por lo general, esto significa que//el componente es binario y no tiene que compilarse antes de su//implementación. Si un componente se implementa como servicio, no//tiene que implementarse por parte de un usuario de un componente.//En vez de ello, se implementa por parte del proveedor del servicio.//Documentado Los componentes deben implementarse por completo, para que los//usuarios potenciales puedan decidir si los componentes cumplen o no//sus necesidades. Debe especificarse la sintaxis y, de manera ideal, la//semántica de todas las interfaces de componente.//Figura 17.1//Características de//los componentes//17.1 ■ Componentes y modelos de componentes 457//Los componentes tienen dos interfaces relacionadas, como se muestra en la figura//17.2. Dichas interfaces reflejan los servicios que proveen los componentes y los servicios//que el componente requiere para ejecutarse correctamente://• La interfaz “proporciona” define los servicios que ofrece el componente. En esencia,//esta interfaz es el componente API. Define los métodos que puede solicitar el usuario//del componente. En un diagrama de componentes UML, la interfaz “proporciona”//para un componente se indica mediante un círculo al final de una línea desde el icono//del componente.//• La interfaz “requiere” especifica qué servicios deben ofrecer otros componentes en//el sistema para que un componente opere correctamente. Si no están disponibles,//entonces el componente no funcionará. Esto no compromete la independencia o el//carácter implementable de un componente, porque la interfaz “requiere” no define//cómo deben proporcionarse dichos servicios. En el UML, el símbolo para una interfaz//“requiere” es un semicírculo al final de una línea desde el icono del componente.//Observe que los iconos de las interfaces “proporciona” y “requiere” pueden encajar//como una articulación de rótula.//Para ilustrar estas interfaces, la figura 17.3 muestra un modelo de componente que se//diseñó para recopilar e intercalar información desde un arreglo de sensores. Se ejecuta de//manera autónoma para recopilar datos durante un cierto tiempo y, a petición, proporciona//datos intercalados a un componente que lo solicite. La interfaz “proporciona” incluye métodos//para agregar, remover, iniciar, detener y probar los sensores. El método report regresa//los datos del sensor que se recopilaron, y el método listAll brinda información de los sensores//unidos. Aunque esto no se muestra aquí, dichos métodos tienen parámetros asociados//que especifican los identificadores del sensor, así como sus ubicaciones, etcétera.//La interfaz “requiere” se usa para conectar el componente a los sensores. Supone que//los sensores tienen una interfaz de datos, a los que se accede a través de sensorData, y//Componente y objetos//Los componentes se implementan con frecuencia en lenguajes orientados a objetos y, en algunos casos,//el acceso a la interfaz “proporciona” de un componente se realiza a través de solicitudes de método. Sin//embargo, los componentes y las clases de objetos no son lo mismo. A diferencia de las clases de objetos, los//componentes se implementan de manera independiente, no son tipos definidos, sino independientes del//lenguaje y se basan en un modelo de componentes estándar.//http://www.SoftwareEngineering-9.com/Web/CBSE/objects.html//Interfaz Requiere//Define los servicios//que se necesitan y//deben proporcionar//otros componentes//Interfaz Proporciona//Define los servicios//que ofrece//el componente//a otros//Componente//Figura 17.2//Interfaces de//componentes//458 Capítulo 17 ■ Ingeniería de software basada en componentes//una interfaz de gestión, a la que se accede a través de sensorManagement. Esta interfaz//se diseñó para conectarse a diferentes tipos de sensor, así que no incluye operaciones de//sensor específicas, tales como Test, provideReading, etcétera. En vez de ello, los comandos//que usa un tipo específico de sensor se incrustan en una cadena, que es un parámetro//para las operaciones en la interfaz “requiere”. Los componentes de adaptador analizan//gramaticalmente ( parse) esta cadena y traducen los comandos incrustados en la interfaz//de control específica de cada tipo de sensor. Más adelante en este capítulo se estudia el//uso de los adaptadores, y se muestra cómo los componentes recolectores de datos se vinculan//con un sensor (figura 17.12).//Una diferencia crucial entre un componente como servicio externo y un componente//como elemento de programa es que los servicios son entidades independientes por completo.//No tienen una interfaz “requiere”. Diferentes programas pueden usar dichos servicios//sin necesidad de implementar soporte adicional requerido por el servicio.//17.1.1 Modelos de componentes//Un modelo de componentes es una definición de estándares para implementación, documentación//y despliegue de componentes. Estos estándares se establecen con la finalidad//de que los desarrolladores de componentes se aseguren de que éstos pueden interoperar.//También funcionan para proveedores de infraestructuras de ejecución de componentes//que ofrecen middleware para apoyar la ejecución de componentes. Se han propuesto//muchos modelos de componentes, pero ahora los modelos más importantes son el//modelo WebServices, el modelo Enterprise Java Beans (EJB) de Sun, y el modelo .NET//de Microsoft (Lau y Wang, 2007).//Weinreich y Sametinger (2001) analizan los elementos básicos de un modelo ideal//de componentes. En la figura 17.4 se resumen esos elementos de modelo. Este diagrama//muestra que los elementos de un modelo de componentes definen las interfaces de componentes,//la información que necesita usar el componente en un programa y cómo debe//implementarse un componente://1. Interfaces Los componentes se definen al especificar sus interfaces. El modelo//de componentes especifica cómo deben definirse las interfaces y los elementos,//tales como los nombres de operación, los parámetros y las excepciones que deben//incluirse en la definición de la interfaz. El modelo también debe especificar el lenguaje//usado para definir las interfaces de componentes. Para servicios Web, éste es//sensorData//sensorManagement//addSensor//removeSensor//startSensor//stopSensor//testSensor//listAll//report//initialize//Interfaz Requiere Interfaz Proporciona//Recolector//de datos//Figura 17.3 Modelo//de componente//recopilador//de datos//17.1 ■ Componentes y modelos de componentes 459//WSDL, que se estudia en el capítulo 19; EJB es específico de Java, de manera que//se usa Java como el lenguaje de definición de interfaz; en .NET, las interfaces se//definen con el Common Intermediate Language (CIL, lenguaje intermedio común).//Algunos modelos de componentes requieren interfaces específicas que deben definirse//por un componente. Se usan para componer el componente con la infraestructura//de modelo de componentes, que ofrece servicios estandarizados, tales como//seguridad y gestión de transacción.//2. Uso Para que los componentes se distribuyan y se acceda a ellos de manera remota,//deben tener un nombre único asociado. Éste debe ser totalmente único, por ejemplo,//en EJB se genera un nombre jerárquico con la raíz basada en un nombre de dominio//de Internet. Los servicios tienen un URI único (Uniform Resource Identifier, esto es,//un identificador de recursos uniforme).//Los metadatos de componente son datos acerca del componente en sí, tales como//información acerca de sus interfaces y atributos. Los metadatos son importantes porque//permiten a los usuarios del componente determinar qué servicios se proporcionan//y requieren. Las implementaciones de modelos de componentes por lo general//incluyen formas específicas (tales como el uso de una interfaz de reflexión en Java)//para acceder a los metadatos de este componente.//Los componentes son entidades genéricas y, cuando se implementan, deben configurarse//para ajustarse en un sistema de aplicación. Por ejemplo, se podría configurar//el componente recolector de datos (figura 17.3) al definir el número máximo de sensores//en un arreglo. Por lo tanto, el modelo de componentes puede especificar cómo//pueden personalizarse los componentes binarios para un entorno de implementación//particular.//3. Implementación El modelo de componentes incluye una especificación de cómo//deben empacarse los componentes para su implementación como entidades ejecutables//independientes. Puesto que los componentes son entidades independientes, deben//empacarse con todo el software de soporte que no proporcione la infraestructura de//componente, o que no esté definido en una interfaz “requiere”. La información//de implementación incluye información sobre el contenido de un paquete y su organización//binaria.//Inevitablemente, conforme surjan nuevos requerimientos, los componentes deberán//cambiarse o sustituirse. Por consiguiente, el modelo de componentes puede incluir//Modelo de componentes//Información//de uso//Definición//de interfaz//Interfaces//específicas//Composición//Convención//de nomenclatura//Acceso a//metadatos//Personalización//Empacado//Documentación//Soporte//de evolución//Interfaces//Implementación//y uso//Figura 17.4 Elementos//básicos de un modelo//de componentes//460 Capítulo 17 ■ Ingeniería de software basada en componentes//reglas que rigen cuándo y cómo se permite la sustitución de componentes. Finalmente,//el modelo de componentes puede definir la documentación de componentes que deba//producirse. Esto se usa para encontrar el componente y decidir si es adecuado.//Para componentes que se implementen como unidades de programa y no como servicios//externos, el modelo de componentes establece los servicios a ofrecer por parte del//middleware que apoye los componentes en ejecución. Weinreich y Sametinger (2001) usan//la analogía de un sistema operativo para explicar los modelos de componentes. Un sistema//operativo brinda un conjunto de servicios genéricos que pueden usar las aplicaciones. La//implementación de un modelo de componentes ofrece servicios compartidos comparables//para los componentes. La figura 17.5 muestra algunos de los servicios que puede ofrecer//una implementación de un modelo de componentes.//Los servicios brindados por una implementación de modelo de componentes se dividen//en dos categorías://1. Servicios de plataforma, los cuales permiten a los componentes comunicarse e interoperar//en un entorno distribuido. Se trata de servicios fundamentales que deben//estar disponibles en todos los sistemas basados en componentes.//2. Servicios de apoyo, que son servicios comunes que probablemente requieran muchos//componentes diversos. Por ejemplo, numerosos componentes requieren autenticación//para garantizar que el usuario de los servicios del componente está autorizado.//Tiene sentido ofrecer un conjunto estándar de servicios middleware para uso de todos//los componentes. Esto reduce los costos del desarrollo de componentes y permite//evitar las incompatibilidades potenciales de los componentes.//El middleware implementa los servicios de componentes y ofrece interfaces a dichos//servicios. Para usar los servicios ofrecidos por la infraestructura de un modelo de componentes,//se puede considerar a los componentes como implementados en un “contenedor”.//Un contenedor es una implementación de los servicios de apoyo más una definición de las//interfaces que debe proporcionar un componente para integrarlo con el contenedor. Incluir//el componente en el contenedor significa que el componente puede ingresar a los servicios//de apoyo, y el contenedor puede acceder a las interfaces de componente. Cuando se usan,//otros componentes no acceden directamente a las interfaces del componente; en vez de//Servicios de plataforma//Servicios de apoyo//Concurrencia//Gestión//de componente//Gestión//de transacción//Persistencia Seguridad//Gestión//de recursos//Direccionamiento Definición//de interfaz//Comunicaciones//de componentes//Gestión//de excepción//Figura 17.5 Servicios//middleware definidos//en un modelo de//componentes//17.2 ■ Procesos CBSE 461//ello, se accede a éstas a través de una interfaz de contenedor que recurre al código para//acceder a la interfaz del componente embebido.//Los contenedores son grandes y complejos, y cuando un componente se implementa//en un contenedor se consigue acceso a todos los servicios middleware. Sin embargo,//los componentes simples tal vez no necesiten todas las instalaciones que ofrece el//middleware de apoyo. Por lo tanto, es un poco diferente el enfoque que se toma en//los servicios Web para el suministro de un servicio común. En el caso de los servicios//Web se han definido estándares para servicios comunes como la gestión de transacciones//y la seguridad, y dichos estándares se implementan como librerías de programa. Si//usted implementa un componente de servicio, sólo utiliza los servicios comunes que//necesita.//17.2 Procesos CBSE//Los procesos CBSE son procesos de software que brindan soporte a la ingeniería de//software basada en componentes. Toman en cuenta las posibilidades de reutilización y//las diferentes actividades de proceso implicadas en el desarrollo y uso de componentes//reutilizables. La figura 17.6 (Kotonya, 2003) ilustra un panorama de los procesos en//CBSE. Al nivel más alto, existen dos tipos de procesos CBSE://1. Desarrollo para reutilización Este proceso se ocupa del desarrollo de componentes//o servicios que se reutilizarán en otras aplicaciones. Por lo regular, implica la//generalización de los componentes existentes.//2. Desarrollo con reutilización Éste es el proceso para desarrollar nuevas aplicaciones//usando los componentes y servicios existentes.//Dichos procesos tienen diferentes objetivos y, por consiguiente, incluyen distintas//actividades. En el proceso de desarrollo para reutilización, el objetivo es producir uno//o más componentes reutilizables. Usted conoce los componentes con los que trabajará y//tiene acceso a su código fuente para generalizarlos. En el desarrollo con reutilización, no//sabe cuáles componentes están disponibles, así que necesita descubrir dichos componentes//y diseñar un sistema para utilizarlos de la manera más efectiva. No puede tener acceso//al código fuente del componente.//En la figura 17.6 se observa que los procesos básicos de CBSE con y para reutilización//tienen procesos de soporte que se ocupan de la adquisición, gestión y certificación//de componentes://1. Adquisición de componentes es el proceso de adquirir componentes para reutilización//o desarrollo en un componente reutilizable. Puede implicar el acceso a componentes//o servicios desarrollados localmente, o encontrar dichos componentes en una//fuente externa.//2. La gestión de componentes se ocupa de la gestión de los componentes de reutilización//de una compañía, asegurándose de que estén adecuadamente catalogados,//almacenados y dispuestos para reutilizarse.//462 Capítulo 17 ■ Ingeniería de software basada en componentes//3. Certificación de componentes es el proceso de comprobar un componente y asegurarse//de que cumple su especificación.//Los componentes que conserva una organización pueden almacenarse en un repositorio//de componentes que incluya tanto los componentes como la información de su uso.//17.2.1 CBSE para reutilización//La CBSE para reutilización es el proceso de desarrollar componentes reutilizables y//ponerlos a disposición para reutilizarlos a través de un sistema de gestión de componentes.//La visión de los primeros defensores de la CBSE (Szyperski, 2002) fue que se desarrollaría//un floreciente mercado de componentes. Habría proveedores especializados de//componentes y vendedores que organizarían la venta de componentes de diferentes desarrolladores.//Los desarrolladores de software comprarían componentes para incluir en//un sistema o pagarían por servicios conforme los utilizaran. Sin embargo, esta visión no se//ha materializado. Existen relativamente pocos proveedores de componentes, y la compra//de componentes es poco común. Al momento de escribir este texto, el mercado de servicios//también está poco desarrollado, aunque hay predicciones de que se expandirá significativamente//durante los próximos años.//En consecuencia, es más probable que la CBSE para reutilización tenga lugar dentro//de una organización que realizó un compromiso con la ingeniería de software dirigida//por la reutilización. En esas circunstancias, se desea aprovechar los activos de software//que se desarrollaron en diferentes partes de la compañía. Sin embargo, tales componentes//desarrollados internamente por lo general no son reutilizables sin cambios. Con frecuencia//incluyen características e interfaces específicas de aplicación que es improbable//que se requieran en otros programas donde se reutilice el componente.//Procesos CBSE//Especificador,//diseñador,//integrador,//mantenedor//Bibliotecario,//vendedor,//corredor//Bibliotecario//Certificador//local o//externo//Fuente//externa//Analista de dominio,//diseñador,//implementador,//mantenedor,//analista de mercado//CBSE para//reutilización//CBSE con//reutilización//Adquisición de//componentes//Certificación de//componentes//Repositorio de//componente//Gestión de//componentes//Figura 17.6 Procesos//CBSE//17.2 ■ Procesos CBSE 463//Para elaborar componentes de reutilización, deben adaptarse y extenderse componentes//específicos de aplicación para crear versiones más genéricas y, por lo tanto, más reutilizables.//Evidentemente, esta adaptación tiene un costo asociado. Así que primero habrá//que decidir si es probable que un componente se reutilice y, segundo, si los ahorros de//costo de la futura reutilización justifican los costos de hacer reutilizable al componente.//Para responder la primera de estas preguntas, se debe decidir si el componente implementa//o no una o más abstracciones de dominio estables. Las abstracciones de dominio//estables son elementos fundamentales del dominio de aplicación que cambian lentamente.//Por ejemplo, en un sistema bancario, las abstracciones de dominio pueden incluir//cuentas, poseedores de cuentas y enunciados. En un sistema de administración de hospitales,//las abstracciones de dominio pueden incluir pacientes, tratamientos y enfermeros.//En ocasiones, a tales abstracciones de dominio se les llama “objetos empresariales”. Si el//componente es una implementación de una abstracción de dominio o un grupo de objetos//empresariales relacionados comúnmente usados, tal vez puedan reutilizarse.//Para responder la pregunta acerca de la efectividad en términos de costo, habrá que//valorar los costos de los cambios que se requieren para hacer reutilizable al componente.//Éstos son los costos de la documentación y validación del componente, y los asociados//con el hecho de hacerlo más genérico. Los cambios que se pueden hacer a un componente//para volverlo más reutilizable incluyen://• eliminar métodos específicos de aplicación;//• cambiar los nombres para hacerlos más generales;//• agregar métodos para brindar cobertura funcional más completa;//• hacer manejadores de excepción consistentes para todos los métodos;//• adicionar una interfaz de “configuración” para permitir la adaptación de los componentes//a diferentes situaciones de uso;//• integrar los componentes requeridos para aumentar la independencia.//El problema del manejo de excepción es particularmente difícil. Los componentes no//deben manejar las excepciones por sí mismos, porque cada aplicación tendrá sus propios//requerimientos para manejo de excepción. En vez de ello, el componente debe definir//qué excepciones pueden surgir y éstas deben publicarse como parte de la interfaz. Por//ejemplo, un componente simple que implemente una estructura de datos en pila debe//detectar y publicar excepciones de desbordamiento (overflow) de pilas y cuando se quiere//extraer de la pila vacía (underflow). Sin embargo, en la práctica, existen dos problemas//con esto://1. Publicar todas las excepciones conduce a interfaces infladas que son difíciles de//entender. Esto podría alejar a usuarios potenciales del componente.//2. La ejecución del componente puede depender del manejo de excepciones locales,//y cambiar esto tal vez tenga serias implicaciones para la funcionalidad del componente.//Mili y sus colaboradores (2002) discuten formas de estimar los costos de hacer reutilizable//un componente y los rendimientos de dicha inversión. Los beneficios de la reutilización//antes de volver a desarrollar un componente no son simplemente ganancias//464 Capítulo 17 ■ Ingeniería de software basada en componentes//en términos de productividad. También existen ganancias de calidad, porque un componente//de reutilización debe ser más confiable, y hay ganancias de tiempo de salida al//mercado. Se trata de un aumento en los rendimientos que se acrecientan al implementar//el software más rápidamente. Mili y sus colaboradores muestran varias fórmulas para//estimar dichas ganancias, como el modelo COCOMO que se estudia en el capítulo 23//(Boehm et al., 2000). Sin embargo, los parámetros de tales fórmulas son difíciles de//evaluar con precisión, y las fórmulas deben adaptarse a circunstancias locales, lo que las//hace más difíciles de usar. Es posible que pocos administradores de proyecto de software//usen estos modelos para estimar el rendimiento sobre la inversión a partir de la reutilización//de componentes.//Desde luego, si un componente es susceptible de reutilización, o no, depende de su//dominio de aplicación y su funcionalidad. Conforme se agrega generalidad a un componente,//aumenta la probabilidad de su reutilización. No obstante, esto por lo regular//significa que el componente tiene más operaciones y más complejidades, las cuales lo//hacen difícil de entender y emplear.//Sin embargo, esto es un intercambio inevitable entre la reutilización y el uso de//un componente. Para hacer reutilizable un componente, usted deberá proporcionar un//conjunto de interfaces genéricas con operaciones que incluyan todas las formas que el//componente podría usar. Hacer un componente utilizable significa ofrecer una interfaz//simple y mínima, que sea fácil de entender. La reutilización agrega complejidad y, por//eso, se dificulta el hecho de entender un componente. Por consiguiente, es más difícil//decidir cuándo y cómo reutilizar dicho componente. En consecuencia, cuando diseñe//un componente de reutilización, debe encontrar un compromiso entre la generalidad y//comprensibilidad.//Una fuente potencial de componentes está constituida por los sistemas heredados//existentes. Como se estudió en el capítulo 9, se trata de sistemas que cumplen una importante//función empresarial, pero que están escritos con tecnologías de software obsoletas.//Por ello, tal vez sea difícil usarlos con sistemas nuevos. Sin embargo, si estos sistemas//antiguos se convierten a componentes, su funcionalidad puede reutilizarse en nuevas//aplicaciones.//Desde luego, estos sistemas heredados no tienen normalmente interfaces “requiere”//y “proporciona” bien definidas. Para hacer reutilizables dichos componentes, debe crear//una envoltura (wrapper) que defina las interfaces de componente. La envoltura oculta//la complejidad del código subyacente y ofrece una interfaz para que los componentes//externos accedan a los servicios que se brindan. Aunque esta envoltura es una pieza de//software bastante compleja, con frecuencia el costo de desarrollarlo es mucho menor//que el costo de volver a implementar el sistema heredado. En el capítulo 19 se examina//con más detalle este enfoque, y se explica cómo puede accederse a las características del//sistema heredado a través de servicios.//Una vez que se ha desarrollado y probado un componente o servicio de reutilización,//entonces debe gestionarse para una reutilización en el futuro. La gestión implica decidir//cómo clasificar el componente de forma que pueda descubrirse, hacer al componente disponible//ya sea en un repositorio o como servicio, mantener información acerca de su uso,//y hacer un seguimiento de las diferentes versiones del componente. Si el componente es//de fuente abierta, se puede hacer disponible en un repositorio público como Sourceforge.//Si se pretende utilizarlo en una compañía, entonces se puede usar un sistema de depósito//interno.//Una compañía con un programa de reutilización puede realizar alguna forma de certificación//de componente antes de que éste se encuentre disponible para su reutilización.//17.2 ■ Procesos CBSE 465//La certificación significa que alguien, aparte del desarrollador, verifica la calidad del//componente. Se prueba el componente y se certifica que alcanza un estándar de calidad//aceptable, antes de ponerlo a disposición para su reutilización. Sin embargo, éste puede//ser un proceso costoso y muchas compañías simplemente dejan las pruebas y la comprobación//de la calidad en manos de los desarrolladores del componente.//17.2.2 CBSE con reutilización//La reutilización exitosa de componentes requiere un proceso de desarrollo ajustado a//CBSE. La CBSE con un proceso de reutilización debe incluir actividades que encuentren//e integren componentes reutilizables. La estructura de tal proceso se trató en el capítulo//2, y la figura 17.7 muestra las principales actividades dentro de ese proceso. Algunas//de las actividades dentro de este proceso, como el descubrimiento inicial de los requerimientos//de usuario, se realizan en la misma forma que en otros procesos de software. Sin//embargo, las diferencias esenciales entre CBSE con reutilización y procesos de software//para desarrollo de software original son://1. Los requerimientos del usuario inicialmente se desarrollan en bosquejos y no en//detalle, y se alienta a las partes interesadas a ser tan flexibles como sea posible//para definir sus requerimientos. Los requerimientos que son demasiado específicos//limitan el número de componentes que pueden satisfacer dichos requerimientos. Sin//embargo, a diferencia del desarrollo incremental, se necesita un conjunto completo//de requerimientos para poder identificar tantos componentes como sea posible para//reutilización.//2. Los requerimientos se afinan y modifican oportunamente durante el proceso, dependiendo//de los componentes disponibles. Si los requerimientos del usuario no pueden//cumplirse a partir de los componentes disponibles, se deberán analizar los requerimientos//relacionados que puedan cumplirse. Los usuarios tal vez tengan voluntad//de cambiar su mentalidad si esto significa entrega de sistema a menor costo o más//rápidamente.//3. Después de diseñar la arquitectura del sistema, hay una actividad adicional de búsqueda//de componentes y clarificación de diseño. Algunos componentes aparentemente//utilizables quizá resulten inadecuados o no funcionen como es debido con//otros componentes elegidos. Aunque no se ilustra en la figura 17.7, esto implica que//pueden ser necesarios posteriores cambios de requerimientos.//Identificar//componentes//candidatos//Bosquejar//los requerimientos//del sistema//Modificar//requerimientos de//acuerdo con componentes//descubiertos//Diseño//arquitectónico//Componer//componentes para//crear el sistema//Identificar//componentes//Figura 17.7 CBSE candidatos//con reutilización//466 Capítulo 17 ■ Ingeniería de software basada en componentes//4. El desarrollo es un proceso de composición en que se integran los componentes descubiertos.//Esto implica integrar los componentes con la infraestructura del modelo//de componentes y, con frecuencia, desarrollar adaptadores que reconcilien las interfaces//de componentes incompatibles. Desde luego, también puede requerirse funcionalidad//adicional por encima de la que ofrecen los componentes de reutilización.//La etapa de diseño arquitectónico es particularmente importante. Jacobson y sus colaboradores//(1997) descubrieron que definir una arquitectura robusta es crucial para tener//éxito en la reutilización. Durante la actividad de diseño arquitectónico, se puede elegir//un modelo de componentes y una plataforma de implementación. Sin embargo, muchas//compañías tienen una plataforma de desarrollo estándar (por ejemplo, .NET), así que el//modelo de componentes está predeterminado. Como se estudió en el capítulo 6, en esta//etapa se establece también la organización de alto nivel del sistema y se toman decisiones//acerca de la distribución y el control del sistema.//Una actividad que es única para el proceso CBSE es identificar los componentes o//servicios candidatos para reutilización. Esto implica algunas actividades específicas,//como se muestra en la figura 17.8. Inicialmente, el enfoque debe estar en la búsqueda//y selección. Es necesario cerciorarse de que hay componentes disponibles para cumplir//los requerimientos. Desde luego, se debe hacer una comprobación inicial de que el componente//es adecuado, aunque es posible que no se requieran pruebas detalladas. En la//última etapa, después de diseñada la arquitectura del sistema, debe dedicarse más tiempo//a la validación de componentes. Hay que estar seguros de que los componentes identificados//son realmente adecuados para su aplicación; si no, entonces habrá que repetir los//procesos de búsqueda y selección.//El primer paso en la identificación de los componentes es buscar aquellos que estén//disponibles localmente o con proveedores confiables. Como se dijo en la sección anterior,//existen relativamente pocos vendedores de componentes, y por eso usted tiene más//probabilidades de buscar los componentes desarrollados en su propia compañía. Las//compañías de desarrollo de software pueden construir su propia base de datos de componentes//de reutilización sin los riesgos inherentes de usar componentes de proveedores//externos. Alternativamente, es posible buscar librerías de código disponibles en la//Web, como Sourceforge o Google Code, para saber si está disponible código fuente para//el componente que se necesita. Si usted busca servicios, en ese caso están disponibles//varios motores de búsqueda Web especializados que pueden descubrir servicios Web//públicos.//Una vez que el proceso de búsqueda permite identificar los posibles componentes, se//deben seleccionar componentes candidatos para su valoración. En algunos casos, ésta//será una labor sencilla. Los componentes en la lista implementarán directamente los//requerimientos del usuario y no habrá componentes competidores que coincidan con//estos requerimientos. Sin embargo, en otros casos, el proceso de selección es mucho más//complejo. No existirá un mapa claro de requerimientos en los componentes y habrá que//integrar muchos componentes para cumplir un requerimiento específico o un conjunto de//Validación//de componentes//Selección//de componentes//Búsqueda//de componentes//Figura 17.8//Proceso de//identificación//de componentes//17.2 ■ Procesos CBSE 467//requerimientos. En consecuencia, se debe decidir cuáles composiciones ofrecen la mejor//cobertura de los requerimientos.//Una vez seleccionados los componentes para su posible inclusión en un sistema, se//deben validar para comprobar que se comportan como se espera. La extensión de la validación//requerida depende de la fuente de los componentes. Si usted usa un componente//que haya desarrollado una fuente conocida y confiable, puede decidir que no es necesaria//la prueba de componentes. Usted simplemente analiza los componentes cuando se integran//con otros. Por otra parte, si utiliza un componente de otras fuentes desconocidas,//siempre deberá comprobar y probar dicho componente antes de incluirlo en su sistema.//La validación de componentes implica desarrollar un conjunto de casos de prueba para//un componente (o, posiblemente, extender los casos de prueba suministrados con dicho//componente) y desarrollar un conjunto de pruebas para ejecutar pruebas de componente. El//principal problema con la validación de componentes es que la especificación de componentes//tal vez no esté suficientemente detallada para permitirle desarrollar un conjunto completo//de pruebas de componentes. Por lo general, los componentes se especifican de manera//informal, y su única documentación formal es la de su especificación de interfaz. Ésta quizá//no incluya suficiente información para desarrollar un conjunto completo de pruebas que lo//convencerían de que la interfaz anunciada del componente es la que requiere.//Además de probar que un componente para reutilización logra lo que se requiere, es//posible que se tenga que verificar también que el componente no incluya algún código//o una funcionalidad maliciosos e innecesarios. Los desarrolladores profesionales pocas//veces usan componentes de fuentes no confiables, en especial si esas fuentes no proporcionan//código fuente. Por lo tanto, el problema de código malicioso no surge habitualmente.//Sin embargo, los componentes con frecuencia pueden contener funcionalidad innecesaria//y se debe comprobar que esta funcionalidad no interfiera con el uso del componente.//El problema con la funcionalidad innecesaria es que puede activarse por el componente//en sí. Esto podría volver lento al componente, hacer que produzca resultados inesperados//o, en algunos casos, provocar fallas graves al sistema. La figura 17.9 resume una situación//en la que la funcionalidad innecesaria en un sistema de reutilización causó una falla catastrófica//del software.//La falla del lanzador Ariane 5//Mientras se desarrollaba el cohete espacial Ariane 5, los diseñadores decidieron reutilizar el software de//referencia inercial que se desempeñó con éxito en el Ariane 4. El software de referencia inercial mantiene la//estabilidad del cohete. Decidieron reutilizarlo sin cambios (como se haría con los componentes), aun cuando//incluía funcionalidad adicional que no se requería en el Ariane 5.//En el primer lanzamiento del Ariane 5 falló el software de navegación inercial y no pudo controlarse el//cohete. Los controladores en tierra instruyeron al lanzador a autodestruirse; así, el cohete y su carga fueron//destruidos. La causa del problema fue una excepción no considerada cuando una conversión de un número//de punto fijo a entero dio por resultado un desbordamiento numérico. Esto hizo que el sistema en tiempo de//ejecución desactivara el sistema de referencia inercial, de manera que no pudo mantenerse la estabilidad//del lanzador. La falla nunca ocurrió en el Ariane 4 porque tenía motores menos poderosos, y el valor que se//convirtió no podía ser suficientemente grande para que la conversión se desbordara.//La falla ocurrió en un código que no se requería en el Ariane 5. Las pruebas de validación para el software//de reutilización se basaron en los requerimientos del Ariane 5. Puesto que no había requerimientos para la//función que falló, no se desarrollaron pruebas. En consecuencia, el problema con el software nunca se descubrió//durante las pruebas de simulación del lanzamiento.//Figura 17.9 Ejemplo//de falla de validación//con software//reutilizado//468 Capítulo 17 ■ Ingeniería de software basada en componentes//El problema en el lanzador Ariane 5 surgió porque las suposiciones acerca del software//para el Ariane 4 eran inválidas para el Ariane 5. Éste es un problema general con los//componentes de reutilización. Originalmente se implementan para un entorno de aplicación//y, como es natural, se incrustan suposiciones acerca de ese entorno. Tales conjeturas//se documentan pocas veces, así que, cuando se reutiliza el componente, es imposible//efectuar pruebas para comprobar si las suposiciones todavía son válidas. Si usted reutiliza//un componente en un entorno distinto, es posible que no descubra las suposiciones//ambientales incrustadas sino hasta que use el componente en un sistema operativo.//17.3 Composición de componentes//La composición de componentes es el proceso de integrar componentes uno con otro y//con “código pegamento” especialmente escrito para crear un sistema u otro componente.//Existen muchas formas diferentes en las que se pueden componer componentes, como//se muestra en la figura 17.10. De izquierda a derecha, dichos diagramas ilustran la composición//secuencial, la composición jerárquica y la composición aditiva. En el siguiente//análisis suponga que compone dos componentes (A y B) para crear uno nuevo://1. La composición secuencial es la situación (a) en la figura 17.10. Usted crea un//nuevo componente a partir de dos componentes existentes al llamar en secuencia a//los componentes existentes. Puede considerar a la composición como una composición//de las “interfaces proporciona”. Esto es, se llaman los servicios ofrecidos por//el componente A y luego los resultados emitidos por A se usan en la llamada a los//servicios que ofrece el componente B. Los componentes no se llaman mutuamente//en composición secuencial. Se requiere algún código pegamento adicional para llamar//los servicios del componente en el orden correcto y asegurar que los resultados//entregados por el componente A sean compatibles con las entradas esperadas por//el componente B. La interfaz “proporciona” de la composición depende de la funcionalidad//combinada de A y B, pero generalmente no será una composición de sus//“interfaces proporciona”. Este tipo de composición puede usarse con componentes//que son elementos de programa o con componentes que son servicios.//2. La composición jerárquica es la situación (b) en la figura 17.10. Este tipo de composición//ocurre cuando un componente llama directamente a los servicios que ofrece//otro componente. El componente llamado proporciona los servicios que requiere el//componente que llama. Por lo tanto, la interfaz “proporciona” del componente llamado//debe ser compatible con la interfaz “requiere” del componente que llama. El//componente A llama al componente B directamente y, si sus interfaces coinciden, tal//vez no haya necesidad de un código adicional. Sin embargo, si existe una discordancia//entre la interfaz “requiere” de A y la interfaz “proporciona” de B, entonces puede//requerirse algún código de conversión. Como los servicios no tienen una interfaz//“requiere”, este modo de composición no se usa cuando los componentes se implementan//como servicios Web.//3. La composición aditiva corresponde a la situación (c) en la figura 17.10. Esto//ocurre cuando dos o más componentes se juntan (se suman) para crear un nuevo//17.3 ■ Composición de componentes 469//componente, lo que combina su funcionalidad. La interfaz “proporciona” y la interfaz//“requiere” del nuevo componente es una combinación de las correspondientes//interfaces en los componentes A y B. Los componentes se llaman por separado//mediante la interfaz externa del componente compuesto. A y B no son dependientes//y no se llaman mutuamente. Este tipo de composición puede usarse con componentes//que son unidades de programa o con componentes que son servicios.//Usted puede usar todas las formas de composición de componentes cuando crea un//sistema. En todos los casos, tal vez tenga que escribir “código pegamento” que vincule//los componentes. Por ejemplo, para composición secuencial, la salida del componente//A se convierte por lo general en la entrada al componente B. Necesitará enunciados//intermedios que llamen al componente A, recolecten el resultado y luego llamen al componente//B con dicho resultado como parámetro. Cuando un componente llama a otro, tal//vez necesite introducir un componente intermedio que asegure que la interfaz “proporciona”//y la interfaz “requiere” sean compatibles.//Cuando escriba nuevos componentes especialmente para composición, deberá diseñar//las interfaces de dichos componentes de manera que sean compatibles con otros componentes//en el sistema. Por consiguiente, puede componer fácilmente dichos componentes//en una sola unidad. No obstante, cuando los componentes se desarrollan de manera independiente//para su reutilización, con frecuencia usted se enfrentará con incompatibilidades//de interfaz. Esto significa que las interfaces de los componentes que desea componer//no son iguales. Es posible que ocurran tres tipos de incompatibilidades://1. Incompatibilidad de parámetro Las operaciones en cada lado de la interfaz tienen//el mismo nombre, pero sus tipos de parámetro o el número de parámetros son diferentes.//2. Incompatibilidad de operación Los nombres de las operaciones en las interfaces//“proporciona” y “requiere” son diferentes.//3. Operación incompleta La interfaz “proporciona” de un componente es un subconjunto//de la interfaz “requiere” de otro componente o viceversa.//En todos los casos, el problema de la incompatibilidad se resuelve al escribir un adaptador//que reconcilie las interfaces de los dos componentes a reutilizar. Un componente//adaptador convierte una interfaz a otra. La forma precisa del adaptador depende del tipo//a)//A A//B B//b) c)//A B//Figura 17.10 Tipos//de composición de//componente//470 Capítulo 17 ■ Ingeniería de software basada en componentes//de composición. En ocasiones, como en el siguiente ejemplo, el adaptador toma un resultado//de un componente y lo convierte en una forma en que puede usarse como entrada a//otro. En otros casos, el adaptador puede llamarse por el componente A como un proxy//para el componente B. Esta situación ocurre si A quiere llamar a B, pero los detalles de la//interfaz “requiere” de A no coinciden con los detalles de la interfaz “proporciona” de B.//El adaptador reconcilia dichas diferencias al convertir sus parámetros de entrada desde//A en los parámetros de entrada requeridos por B. Entonces llama a B para entregar los//servicios requeridos por A.//Para ilustrar los adaptadores, considere los dos componentes que se muestran en la//figura 17.11, cuyas interfaces son incompatibles. Esto puede ser parte de un sistema usado//por los servicios de emergencia. Cuando el operador de emergencia recibe una llamada,//el número telefónico se ingresa al componente addressFinder para localizar la dirección.//Entonces, al usar el componente mapper, el operador imprime un mapa para mandarlo//al vehículo que acude a la emergencia. De hecho, los componentes tendrían interfaces//más complejas que las mostradas aquí, pero la versión simplificada ilustra el concepto de//adaptador.//El primer componente, addressFinder, encuentra la dirección que coincide con un//número telefónico. También puede regresar al dueño de la propiedad asociada con el número//telefónico y el tipo de propiedad. El componente mapper toma un código postal//(en Estados Unidos, un código ZIP estándar con los cuatro dígitos adicionales que identifican//la ubicación de la propiedad) y muestra o imprime un mapa de las calles del área//que rodean dicho código a una escala específica.//Tales componentes se pueden componer, en principio, porque la ubicación de la propiedad//incluye un código postal o ZIP. Sin embargo, se debe escribir un componente//adaptador llamado postCodeStripper que toma los datos de ubicación del addressFinder//y consigue el código postal. Entonces este código postal se usa como entrada a mapper, y//el mapa de las calles se muestra a una escala de 1:10,000. El siguiente código, que es un//ejemplo de composición secuencial, ilustra la secuencia de llamadas que se requieren//para implementar esto://address = addressFinder.location (phonenumber) ;//postCode = postCodeStripper.getPostCode (address) ;//mapper.displayMap(postCode, 10000) ;//phoneDatabase (cadena command)//cadena location (cadena pn)//cadena owner (cadena pn)//cadena propertyType (cadena pn)//mapDB (cadena command)//displayMap (cadena postCode, scale)//printMap (cadena postCode, scale)//addressFinder//mapper//Figura 17.11//Componentes con//interfaces incompatibles//17.3 ■ Composición de componentes 471//Otro caso en el que puede usarse un componente adaptador es el de la composición//jerárquica, donde un componente quiere usar otro, pero existe una incompatibilidad entre//la interfaz “proporciona” y la interfaz “requiere” de los componentes en la composición.//En la figura 17.12 se ilustra el uso de un adaptador que vincula un recolector de datos y//un componente sensor. Esto podría usarse en la implementación de un sistema de estación//meteorológica a campo abierto, como se estudió en el capítulo 7.//Los componentes sensor y recolector de datos se componen usando un adaptador//que reconcilia la interfaz “requiere” del componente de recolección de datos con la//interfaz “proporciona” del componente sensor. El componente recolector de datos se//diseñó con una interfaz “requiere” genérica que brinda soporte a la recolección de//datos del sensor y la gestión del sensor. Para cada una de dichas operaciones, el parámetro//es una cadena de texto que representa los comandos de sensor específicos. Por//ejemplo, para emitir un comando de recolección (collect), diría sensorData(“collect”).//Como se muestra en la figura 17.12, el sensor en sí tiene operaciones separadas como//start, stop y getdata.//El adaptador analiza gramaticalmente la cadena de entrada, identifica el comando//(por ejemplo, collect) y luego llama a Sensor.getdata para recolectar el valor del sensor.//Luego, regresa el resultado (como una cadena de caracteres) al componente recolector//de datos. Este estilo de interfaz significa que el recolector de datos puede interactuar//con diferentes tipos de sensor. Un adaptador separado, que convierte los comandos del//sensor de Recolector de datos a la interfaz de sensor real, se implementa para cada tipo//de sensor.//El análisis anterior de composición supone que usted puede decir, a partir de la documentación//del componente, si las interfaces son compatibles o no. Desde luego, la definición//de interfaz incluye el nombre de la operación y los tipos de parámetro, de manera//que se puede hacer cierta valoración de la compatibilidad a partir de esto. Sin embargo,//usted depende de la documentación del componente para decidir si las interfaces son//semánticamente compatibles.//Para ilustrar este problema, considere la composición que se ilustra en la figura//17.13. Dichos componentes se usan para implementar un sistema que descargue imágenes//de una cámara digital y las almacene en una fototeca. El usuario del sistema puede//dar información adicional para describir y catalogar la fotografía. Para evitar confusión,//aquí no se muestran todos los métodos de interfaz. En vez de ello, simplemente se//addSensor//removeSensor//startSensor//stopSensor//testSensor//listAll//report//initialize//sensorManagement//sensorData//Sensor Adaptador//start//getdata//stop//Recolector//de datos//Figura 17.12//Adaptador que vincula//un recolector de datos//y un sensor//472 Capítulo 17 ■ Ingeniería de software basada en componentes//indican los métodos que se necesitan para ejemplificar el problema de la documentación//de componentes. Los métodos en la interfaz de Fototeca son://public void addItem (Identifier pid ; Photograph p; CatalogEntry//photodesc) ;//public Photograph retrieve (Identifier pid) ;//public CatalogEntry catEntry (Identifier pid);//Suponga que la documentación para el método addItem en Fototeca es://Este método agrega una fotografía a la fototeca y asocia el identificador de la//fotografía, y cataloga el descriptor con la fotografía.//Esta descripción explica qué hace el componente; sin embargo, considere las siguientes//preguntas://• ¿Qué sucede si el identificador de fotografía ya está asociado con una fotografía en la//fototeca?//• ¿El descriptor de fotografía está asociado con la entrada de catálogo, al igual que//la fotografía? Esto es, si borra la fotografía, ¿también borra la información del catálogo?//No hay suficiente información en la descripción informal de addItem para responder//dichas preguntas. Desde luego, es posible agregar más información a la descripción en//lenguaje natural del método, pero, en general, la mejor forma de resolver ambigüedades//es usar un lenguaje formal para describir la interfaz. La especificación que se muestra//en la figura 17.14 es parte de la descripción de la interfaz de Fototeca que agrega información//a la descripción informal.//La especificación en la figura 17.14 usa precondiciones y post-condiciones que se definen//en una notación con base en el lenguaje de restricción de objeto (OCL), que es parte//del UML (Warmer y Kleppe, 2003). OCL está diseñado para describir restricciones en//modelos de objetos UML; permite expresar predicados que deben ser verdaderos siempre,//que deben ser verdaderos antes de ejecutar un método, y qué deben ser verdaderos//Fototeca//Adaptador Gestor//de imagen//getImage//Interfaz//de usuario//getCatalogEntry//addItem//retrieve//catEntry//Figura 17.13//Composición//de fototeca//17.3 ■ Composición de componentes 473//después de ejecutar un método. Se trata de invariantes, precondiciones y post-condiciones.//Para acceder al valor de una variable antes de una operación, agregue @pre después de su//nombre. Por lo tanto, al usar la edad como ejemplo://age = age@pre + 1//Este enunciado significa que el valor de la edad después de una operación es uno más//del que era antes de dicha operación.//Los enfoques basados en OCL se usan cada vez más para agregar información semántica//a modelos UML, y las descripciones OCL pueden usarse para derivar generadores//de código en ingeniería dirigida por modelo. El enfoque general se derivó del enfoque//Diseño por Contrato, de Meyer (Meyer, 1992), en el que las interfaces y obligaciones de//los objetos en comunicación se especifican formalmente y se refuerzan por el sistema al//tiempo de ejecución. Meyer sugiere que usar Diseño por Contrato es esencial si usted//debe desarrollar componentes confiables (Meyer, 2003).//La figura 17.14 incluye una especificación para los métodos addItem y delete en//Fototeca. El método a especificar se indica mediante el contexto de palabra clave, y las//precondiciones y post-condiciones mediante las palabras clave pre y post. Las precondiciones//para addItem afirman que://1. No debe haber una fotografía en la fototeca con el mismo identificador que la fotografía//a ingresar.//2. Debe existir la fototeca: suponga que crear una fototeca agrega un solo ítem en ella,//de manera que el tamaño de una fototeca siempre es mayor que cero.//— La palabra clave del contexto menciona el componente al que se aplican las//condiciones//context addItem//— Las precondiciones especifican qué debe ser verdadero antes de ejecutar addItem//pre: PhotoLibrary.libSize() > 0//PhotoLibrary.retrieve(pid) = null//— Las post-condiciones especifican qué es verdadero después de la ejecución//post: libSize () = libSize()@pre + 1//PhotoLibrary.retrieve(pid) = p//PhotoLibrary.catEntry(pid) = photodesc//context delete//pre: PhotoLibrary.retrieve(pid) null ;//post: PhotoLibrary.retrieve(pid) = null//PhotoLibrary.catEntry(pid) = PhotoLibrary.catEntry(pid)@pre//PhotoLibrary.libSize() = libSize()@pre—1//Figura 17.14//Descripción OCL de la//interfaz Fototeca//474 Capítulo 17 ■ Ingeniería de software basada en componentes//3. Las post-condiciones para addItem afirman que://El tamaño de la fototeca aumentó por 1 (de manera que únicamente se realizó//una sola entrada).//Si usted recupera usando el mismo identificador, entonces recupera la fotografía//que agregó.//Si busca el catálogo usando dicho identificador, recupera la entrada catálogo que//realizó.//La especificación delete brinda más información. La precondición afirma que, para//borrar un ítem, éste debe estar en la fototeca y, después del borrado, la fotografía ya no//podrá recuperarse y el tamaño de la fototeca se reducirá en 1. Sin embargo, delete no borra//la entrada de catálogo: todavía es posible recuperarla después de borrar la fotografía. La//razón de esto es que tal vez usted quiera mantener información en el catálogo acer ca de//por qué borró una fotografía, su nueva ubicación, etcétera.//Cuando usted crea un sistema al componer componentes, puede descubrir que hay//conflictos potenciales entre requerimientos funcionales y no funcionales, o entre la necesidad//de entregar un sistema tan rápidamente como sea posible y la necesidad de crear//un sistema que puede evolucionar conforme cambian los requerimientos. Las decisiones//donde puede tomar en cuenta negociaciones son://1. ¿Qué composición es más efectiva para entregar los requerimientos funcionales del//sistema?//2. ¿Qué composición facilitará la adaptación del componente cuando cambien los//requerimientos?//3. ¿Cuáles serán las propiedades emergentes del sistema compuesto? Se trata de propiedades//como rendimiento y confiabilidad. Sólo podrá valorarlos una vez que se//implemente el sistema completo.//Por desgracia, existen muchas situaciones donde las soluciones a los problemas de//composición podrían estar en conflicto. Por ejemplo, considere una situación como la//que se ilustra en la figura 17.15, donde puede crear un sistema mediante dos composiciones//alternativas. El sistema es una colección de datos y un sistema de reporte donde//se recopilan datos de diferentes fuentes, se almacenan en una base de datos y luego se//generan diferentes informes que resumen dichos datos.//Aquí, existe un conflicto potencial entre adaptabilidad y rendimiento. La composición//a) es más adaptable, pero la composición b) tal vez es más rápida y más fiable.//Las ventajas de la composición a) son que los reportes y la gestión de datos están separados,//de manera que hay más flexibilidad para un cambio en el futuro. El sistema de//gestión de datos podría sustituirse y, si se requieren reportes que el actual componente//de reporte no puede generar, también es posible sustituir dicho componente sin tener//que cambiar el componente de gestión de datos.//En la composición b) se usa un componente de base de datos con instalaciones de//reporte incorporadas (por ejemplo, Microsoft Access). La ventaja clave de la composición//b) es que existen menos componentes, de manera que será una implementación más//Capítulo 17 ■ Puntos clave 475//rápida porque no hay cargas de comunicación del componente. Más aún, las reglas de//integridad de datos que se aplican a la base de datos también se aplicarán a los reportes.//Dichos reportes no podrán combinar datos en formas incorrectas. En la composición a),//no hay tales restricciones, de manera que podrían ocurrir errores en los reportes.//En general, un buen principio de composición a seguir es el principio de separación//de asuntos. Esto es, debe tratar de diseñar su sistema de tal forma que cada componente//tenga un papel claramente definido y que, de manera ideal, dichos roles no se traslapen.//Sin embargo, quizá sea menos costoso comprar un componente multifuncional en vez//de dos o tres componentes separados. Más aún, podría haber sanciones en términos de la//confiabilidad o el rendimiento cuando se usan múltiples componentes.//
Deja un comentario